summaryrefslogtreecommitdiff
path: root/isam
diff options
context:
space:
mode:
authorunknown <bk@work.mysql.com>2000-07-31 21:29:14 +0200
committerunknown <bk@work.mysql.com>2000-07-31 21:29:14 +0200
commit2e94af465deb4af39c7a2a6330fd49f3254b5daa (patch)
treed253a359142dfc1ed247d5d4365d86972ea31109 /isam
parent78f5c3123dde27170c47ad9e5c95f9f507d550cb (diff)
downloadmariadb-git-2e94af465deb4af39c7a2a6330fd49f3254b5daa.tar.gz
Import changeset
Docs/Flags/australia.eps: First import - 3.23.10 Docs/Flags/australia.gif: First import - 3.23.10 Docs/Flags/australia.txt: First import - 3.23.10 Docs/Flags/austria.eps: First import - 3.23.10 Docs/Flags/austria.gif: First import - 3.23.10 Docs/Flags/austria.txt: First import - 3.23.10 Docs/Flags/brazil.eps: First import - 3.23.10 Docs/Flags/brazil.gif: First import - 3.23.10 Docs/Flags/brazil.txt: First import - 3.23.10 Docs/Flags/bulgaria.eps: First import - 3.23.10 Docs/Flags/bulgaria.gif: First import - 3.23.10 Docs/Flags/bulgaria.txt: First import - 3.23.10 Docs/Flags/canada.eps: First import - 3.23.10 Docs/Flags/canada.gif: First import - 3.23.10 Docs/Flags/canada.txt: First import - 3.23.10 Docs/Flags/chile.eps: First import - 3.23.10 Docs/Flags/chile.gif: First import - 3.23.10 Docs/Flags/chile.txt: First import - 3.23.10 Docs/Flags/china.eps: First import - 3.23.10 Docs/Flags/china.gif: First import - 3.23.10 Docs/Flags/china.txt: First import - 3.23.10 Docs/Flags/croatia.eps: First import - 3.23.10 Docs/Flags/croatia.gif: First import - 3.23.10 Docs/Flags/croatia.txt: First import - 3.23.10 Docs/Flags/czech-republic.eps: First import - 3.23.10 Docs/Flags/czech-republic.gif: First import - 3.23.10 Docs/Flags/czech-republic.txt: First import - 3.23.10 Docs/Flags/denmark.eps: First import - 3.23.10 Docs/Flags/denmark.gif: First import - 3.23.10 Docs/Flags/denmark.txt: First import - 3.23.10 Docs/Flags/estonia.eps: First import - 3.23.10 Docs/Flags/estonia.gif: First import - 3.23.10 Docs/Flags/estonia.txt: First import - 3.23.10 Docs/Flags/finland.eps: First import - 3.23.10 Docs/Flags/finland.gif: First import - 3.23.10 Docs/Flags/finland.txt: First import - 3.23.10 Docs/Flags/france.eps: First import - 3.23.10 Docs/Flags/france.gif: First import - 3.23.10 Docs/Flags/france.txt: First import - 3.23.10 Docs/Flags/germany.eps: First import - 3.23.10 Docs/Flags/germany.gif: First import - 3.23.10 Docs/Flags/germany.txt: First import - 3.23.10 Docs/Flags/great-britain.eps: First import - 3.23.10 Docs/Flags/great-britain.gif: First import - 3.23.10 Docs/Flags/great-britain.txt: First import - 3.23.10 Docs/Flags/greece.eps: First import - 3.23.10 Docs/Flags/greece.gif: First import - 3.23.10 Docs/Flags/greece.txt: First import - 3.23.10 Docs/Flags/hungary.eps: First import - 3.23.10 Docs/Flags/hungary.gif: First import - 3.23.10 Docs/Flags/hungary.txt: First import - 3.23.10 Docs/Flags/iceland.eps: First import - 3.23.10 Docs/Flags/iceland.gif: First import - 3.23.10 Docs/Flags/iceland.txt: First import - 3.23.10 Docs/Flags/ireland.eps: First import - 3.23.10 Docs/Flags/ireland.gif: First import - 3.23.10 Docs/Flags/ireland.txt: First import - 3.23.10 Docs/Flags/island.eps: First import - 3.23.10 Docs/Flags/island.gif: First import - 3.23.10 Docs/Flags/island.txt: First import - 3.23.10 Docs/Flags/israel.eps: First import - 3.23.10 Docs/Flags/israel.gif: First import - 3.23.10 Docs/Flags/israel.txt: First import - 3.23.10 Docs/Flags/italy.eps: First import - 3.23.10 Docs/Flags/italy.gif: First import - 3.23.10 Docs/Flags/italy.txt: First import - 3.23.10 Docs/Flags/japan.eps: First import - 3.23.10 Docs/Flags/japan.gif: First import - 3.23.10 Docs/Flags/japan.txt: First import - 3.23.10 Docs/Flags/kroatia.eps: First import - 3.23.10 Docs/Flags/kroatia.gif: First import - 3.23.10 Docs/Flags/kroatia.txt: First import - 3.23.10 Docs/Flags/netherlands.eps: First import - 3.23.10 Docs/Flags/netherlands.gif: First import - 3.23.10 Docs/Flags/netherlands.txt: First import - 3.23.10 Docs/Flags/poland.eps: First import - 3.23.10 Docs/Flags/poland.gif: First import - 3.23.10 Docs/Flags/poland.txt: First import - 3.23.10 Docs/Flags/portugal.eps: First import - 3.23.10 Docs/Flags/portugal.gif: First import - 3.23.10 Docs/Flags/portugal.txt: First import - 3.23.10 Docs/Flags/romania.eps: First import - 3.23.10 Docs/Flags/romania.gif: First import - 3.23.10 Docs/Flags/romania.txt: First import - 3.23.10 Docs/Flags/russia.eps: First import - 3.23.10 Docs/Flags/russia.gif: First import - 3.23.10 Docs/Flags/russia.txt: First import - 3.23.10 Docs/Flags/singapore.eps: First import - 3.23.10 Docs/Flags/singapore.gif: First import - 3.23.10 Docs/Flags/singapore.txt: First import - 3.23.10 Docs/Flags/south-africa.eps: First import - 3.23.10 Docs/Flags/south-africa.gif: First import - 3.23.10 Docs/Flags/south-africa.txt: First import - 3.23.10 Docs/Flags/south-africa1.eps: First import - 3.23.10 Docs/Flags/south-africa1.gif: First import - 3.23.10 Docs/Flags/south-africa1.txt: First import - 3.23.10 Docs/Flags/south-korea.eps: First import - 3.23.10 Docs/Flags/south-korea.gif: First import - 3.23.10 Docs/Flags/south-korea.txt: First import - 3.23.10 Docs/Flags/spain.eps: First import - 3.23.10 Docs/Flags/spain.gif: First import - 3.23.10 Docs/Flags/spain.txt: First import - 3.23.10 Docs/Flags/sweden.eps: First import - 3.23.10 Docs/Flags/sweden.gif: First import - 3.23.10 Docs/Flags/sweden.txt: First import - 3.23.10 Docs/Flags/switzerland.eps: First import - 3.23.10 Docs/Flags/switzerland.gif: First import - 3.23.10 Docs/Flags/switzerland.txt: First import - 3.23.10 Docs/Flags/taiwan.eps: First import - 3.23.10 Docs/Flags/taiwan.gif: First import - 3.23.10 Docs/Flags/taiwan.txt: First import - 3.23.10 Docs/Flags/ukraine.eps: First import - 3.23.10 Docs/Flags/ukraine.gif: First import - 3.23.10 Docs/Flags/ukraine.txt: First import - 3.23.10 Docs/Flags/usa.eps: First import - 3.23.10 Docs/Flags/usa.gif: First import - 3.23.10 Docs/Flags/usa.txt: First import - 3.23.10 Docs/Images/mysql-logo.gif: First import - 3.23.10 Docs/To-be-included-in-the-manual/MySQL-for-dummies: First import - 3.23.10 README: First import - 3.23.10 config.guess: First import - 3.23.10 dbug/dbug_long.h: First import - 3.23.10 dbug/example1.c: First import - 3.23.10 dbug/example2.c: First import - 3.23.10 dbug/example3.c: First import - 3.23.10 dbug/factorial.c: First import - 3.23.10 dbug/main.c: First import - 3.23.10 dbug/monty.doc: First import - 3.23.10 dbug/readme.prof: First import - 3.23.10 dbug/sanity.c: First import - 3.23.10 dbug/user.r: First import - 3.23.10 heap/ChangeLog: First import - 3.23.10 install-sh: First import - 3.23.10 ltconfig: First import - 3.23.10 ltmain.sh: First import - 3.23.10 missing: First import - 3.23.10 mit-pthreads/COPYRIGHT: First import - 3.23.10 mit-pthreads/FAQ: First import - 3.23.10 mit-pthreads/NOTES_OSR5_BUILD_SKUNKWARE97: First import - 3.23.10 mit-pthreads/NOTES: First import - 3.23.10 mit-pthreads/README: First import - 3.23.10 mit-pthreads/TODO-mysql: First import - 3.23.10 mit-pthreads/Whats_New: First import - 3.23.10 mit-pthreads/bin/Makefile.in: First import - 3.23.10 mit-pthreads/bin/finger/Makefile.in: First import - 3.23.10 mit-pthreads/bin/finger/finger.c: First import - 3.23.10 mit-pthreads/bin/finger/net.c: First import - 3.23.10 mit-pthreads/config/COPYING.GNU: First import - 3.23.10 mit-pthreads/config/COPYRIGHT: First import - 3.23.10 mit-pthreads/config/GNUmakefile.in: First import - 3.23.10 mit-pthreads/config/Makefile.in: First import - 3.23.10 mit-pthreads/config/acconfig.h: First import - 3.23.10 mit-pthreads/config/aclocal.m4: First import - 3.23.10 mit-pthreads/config/config.flags.in: First import - 3.23.10 mit-pthreads/config/config.guess: First import - 3.23.10 mit-pthreads/config/config.sub: First import - 3.23.10 mit-pthreads/config/configure.org: First import - 3.23.10 mit-pthreads/config/install-sh: First import - 3.23.10 mit-pthreads/configure: First import - 3.23.10 mit-pthreads/gen/GNUmakefile.inc: First import - 3.23.10 mit-pthreads/gen/Makefile.inc: First import - 3.23.10 mit-pthreads/gen/ctime.c: First import - 3.23.10 mit-pthreads/gen/difftime.c: First import - 3.23.10 mit-pthreads/gen/directory.c: First import - 3.23.10 mit-pthreads/gen/eprintf.c: First import - 3.23.10 mit-pthreads/gen/getcwd.c: First import - 3.23.10 mit-pthreads/gen/getpwent.c: First import - 3.23.10 mit-pthreads/gen/getpwnamuid.c: First import - 3.23.10 mit-pthreads/gen/getwd.c: First import - 3.23.10 mit-pthreads/gen/isatty.c: First import - 3.23.10 mit-pthreads/gen/popen.c: First import - 3.23.10 mit-pthreads/gen/pwd_internal.c: First import - 3.23.10 mit-pthreads/gen/pwd_internal.h: First import - 3.23.10 mit-pthreads/gen/syslog.c: First import - 3.23.10 mit-pthreads/gen/time.c: First import - 3.23.10 mit-pthreads/include/Makefile.inc: First import - 3.23.10 mit-pthreads/include/arpa/inet.h: First import - 3.23.10 mit-pthreads/include/arpa/nameser.h: First import - 3.23.10 mit-pthreads/include/dirent.h: First import - 3.23.10 mit-pthreads/include/endian.h: First import - 3.23.10 mit-pthreads/include/errno.h: First import - 3.23.10 mit-pthreads/include/math.h: First import - 3.23.10 mit-pthreads/include/netdb.h: First import - 3.23.10 mit-pthreads/include/pthread.h: First import - 3.23.10 mit-pthreads/include/pthread/cleanup.h: First import - 3.23.10 mit-pthreads/include/pthread/debug_out.h: First import - 3.23.10 mit-pthreads/include/pthread/fd.h: First import - 3.23.10 mit-pthreads/include/pthread/fd_pipe.h: First import - 3.23.10 mit-pthreads/include/pthread/kernel.h: First import - 3.23.10 mit-pthreads/include/pthread/kthread.h: First import - 3.23.10 mit-pthreads/include/pthread/mutex.h: First import - 3.23.10 mit-pthreads/include/pthread/prio_queue.h: First import - 3.23.10 mit-pthreads/include/pthread/pthread_attr.h: First import - 3.23.10 mit-pthreads/include/pthread/pthread_once.h: First import - 3.23.10 mit-pthreads/include/pthread/queue.h: First import - 3.23.10 mit-pthreads/include/pthread/sleep.h: First import - 3.23.10 mit-pthreads/include/pthread/specific.h: First import - 3.23.10 mit-pthreads/include/pthread/state.def: First import - 3.23.10 mit-pthreads/include/pthread/types.h: First import - 3.23.10 mit-pthreads/include/pthread/unistd.h: First import - 3.23.10 mit-pthreads/include/pthread/util.h: First import - 3.23.10 mit-pthreads/include/pthread/version.h: First import - 3.23.10 mit-pthreads/include/pthread/xtypes.h: First import - 3.23.10 mit-pthreads/include/pwd.h: First import - 3.23.10 mit-pthreads/include/resolv.h: First import - 3.23.10 mit-pthreads/include/sched.h: First import - 3.23.10 mit-pthreads/include/signal.h: First import - 3.23.10 mit-pthreads/include/stdio.h: First import - 3.23.10 mit-pthreads/include/stdlib.h: First import - 3.23.10 mit-pthreads/include/string.h: First import - 3.23.10 mit-pthreads/include/syslog.h: First import - 3.23.10 mit-pthreads/include/time.h: First import - 3.23.10 mit-pthreads/include/timers.h: First import - 3.23.10 mit-pthreads/include/tzfile.h: First import - 3.23.10 mit-pthreads/include/unistd.h: First import - 3.23.10 mit-pthreads/lib/Makefile.in: First import - 3.23.10 mit-pthreads/lib/libpthreadutil/Makefile.in: First import - 3.23.10 mit-pthreads/lib/libpthreadutil/pthread_atexit.c: First import - 3.23.10 mit-pthreads/lib/libpthreadutil/pthread_tad.c: First import - 3.23.10 mit-pthreads/lib/libpthreadutil/pthreadutil.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/__math.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/__signal.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/__string.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/__time.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/cdefs.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/compat.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/dirent.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/signal.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/socket.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/timers.h: First import - 3.23.10 mit-pthreads/machdep/alpha-osf1/uio.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-1.1/compat.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-1.1/dirent.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-1.1/errno.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-1.1/socket.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-1.1/timers.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/__math.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/__path.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/__signal.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/__string.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/__time.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/compat.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/dirent.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/errno.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/time.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/timers.h: First import - 3.23.10 mit-pthreads/machdep/bsdi-2.0/wait.h: First import - 3.23.10 mit-pthreads/machdep/engine-alpha-netbsd-1.1.c: First import - 3.23.10 mit-pthreads/machdep/engine-alpha-netbsd-1.1.h: First import - 3.23.10 mit-pthreads/machdep/engine-alpha-netbsd-1.3.c: First import - 3.23.10 mit-pthreads/machdep/engine-alpha-netbsd-1.3.h: First import - 3.23.10 mit-pthreads/machdep/engine-alpha-osf1.c: First import - 3.23.10 mit-pthreads/machdep/engine-alpha-osf1.h: First import - 3.23.10 mit-pthreads/machdep/engine-arm32-netbsd-1.3.c: First import - 3.23.10 mit-pthreads/machdep/engine-arm32-netbsd-1.3.h: First import - 3.23.10 mit-pthreads/machdep/engine-hppa-hpux-10.20.c: First import - 3.23.10 mit-pthreads/machdep/engine-hppa-hpux-10.20.h: First import - 3.23.10 mit-pthreads/machdep/engine-hppa-hpux-9.03.c: First import - 3.23.10 mit-pthreads/machdep/engine-hppa-hpux-9.03.h: First import - 3.23.10 mit-pthreads/machdep/engine-i386-bsdi-1.1.c: First import - 3.23.10 mit-pthreads/machdep/engine-i386-bsdi-1.1.h: First import - 3.23.10 mit-pthreads/machdep/engine-i386-bsdi-2.0.c: First import - 3.23.10 mit-pthreads/machdep/engine-i386-bsdi-2.0.h: First import - 3.23.10 mit-pthreads/machdep/engine-i386-freebsd-1.1.c: First import - 3.23.10 mit-pthreads/machdep/engine-i386-freebsd-1.1.h: First import - 3.23.10 mit-pthreads/machdep/engine-i386-freebsd-2.0.c: First import - 3.23.10 mit-pthreads/machdep/engine-i386-freebsd-2.0.h: First import - 3.23.10 mit-pthreads/machdep/engine-i386-linux-1.0.c: First import - 3.23.10 mit-pthreads/machdep/engine-i386-linux-1.0.h: First import - 3.23.10 mit-pthreads/machdep/engine-i386-netbsd-0.9.c: First import - 3.23.10 mit-pthreads/machdep/engine-i386-netbsd-0.9.h: First import - 3.23.10 mit-pthreads/machdep/engine-i386-netbsd-1.0.c: First import - 3.23.10 mit-pthreads/machdep/engine-i386-netbsd-1.0.h: First import - 3.23.10 mit-pthreads/machdep/engine-i386-netbsd-1.3.c: First import - 3.23.10 mit-pthreads/machdep/engine-i386-netbsd-1.3.h: First import - 3.23.10 mit-pthreads/machdep/engine-i386-openbsd-2.0.c: First import - 3.23.10 mit-pthreads/machdep/engine-i386-openbsd-2.0.h: First import - 3.23.10 mit-pthreads/machdep/engine-i386-sco-3.2v5.c: First import - 3.23.10 mit-pthreads/machdep/engine-i386-sco-3.2v5.h: First import - 3.23.10 mit-pthreads/machdep/engine-ip22-irix-5.2.c: First import - 3.23.10 mit-pthreads/machdep/engine-ip22-irix-5.2.h: First import - 3.23.10 mit-pthreads/machdep/engine-m68000-netbsd.c: First import - 3.23.10 mit-pthreads/machdep/engine-m68000-netbsd.h: First import - 3.23.10 mit-pthreads/machdep/engine-r2000-ultrix-4.2.c: First import - 3.23.10 mit-pthreads/machdep/engine-r2000-ultrix-4.2.h: First import - 3.23.10 mit-pthreads/machdep/engine-romp-bsd.c: First import - 3.23.10 mit-pthreads/machdep/engine-romp-bsd.h: First import - 3.23.10 mit-pthreads/machdep/engine-sparc-netbsd-1.3.c: First import - 3.23.10 mit-pthreads/machdep/engine-sparc-netbsd-1.3.h: First import - 3.23.10 mit-pthreads/machdep/engine-sparc-sunos-4.1.3.c: First import - 3.23.10 mit-pthreads/machdep/engine-sparc-sunos-4.1.3.h: First import - 3.23.10 mit-pthreads/machdep/engine-sparc-sunos-5.3.c: First import - 3.23.10 mit-pthreads/machdep/engine-sparc-sunos-5.3.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-1.1/compat.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-1.1/dirent.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-1.1/socket.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-1.1/timers.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/__math.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/__path.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/__signal.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/__string.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/__time.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/compat.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/dirent.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/errno.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/timers.h: First import - 3.23.10 mit-pthreads/machdep/freebsd-2.0/wait.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/__math.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/__signal.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/__string.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/__time.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/cdefs.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/compat.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/dirent.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/socket.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/stdtypes.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/time.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/timers.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/uio.h: First import - 3.23.10 mit-pthreads/machdep/hpux-10.20/wait.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/__math.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/__signal.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/__string.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/__time.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/cdefs.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/compat.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/dirent.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/socket.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/stdtypes.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/time.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/timers.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/uio.h: First import - 3.23.10 mit-pthreads/machdep/hpux-9.03/wait.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/__math.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/__signal.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/__string.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/__time.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/compat.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/dirent.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/posix/__signal.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/socket.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/syscall.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/timers.h: First import - 3.23.10 mit-pthreads/machdep/i386-sco-3.2v5/trash.can: First import - 3.23.10 mit-pthreads/machdep/irix-5.2/__math.h: First import - 3.23.10 mit-pthreads/machdep/irix-5.2/__signal.h: First import - 3.23.10 mit-pthreads/machdep/irix-5.2/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/irix-5.2/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/irix-5.2/__string.h: First import - 3.23.10 mit-pthreads/machdep/irix-5.2/__time.h: First import - 3.23.10 mit-pthreads/machdep/irix-5.2/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/irix-5.2/compat.h: First import - 3.23.10 mit-pthreads/machdep/irix-5.2/dirent.h: First import - 3.23.10 mit-pthreads/machdep/irix-5.2/socket.h: First import - 3.23.10 mit-pthreads/machdep/irix-5.2/timers.h: First import - 3.23.10 mit-pthreads/machdep/irix-5.2/wait.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/__math.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/__path.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/__signal.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/__string.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/__time.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/cdefs.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/compat.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/dirent.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/errno.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/socket.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/timers.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/uio.h: First import - 3.23.10 mit-pthreads/machdep/linux-1.0/wait.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-0.9/dirent.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/__math.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/__path.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/__signal.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/__string.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/__time.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/compat.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/dirent.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/errno.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/time.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/timers.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.0/wait.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/__math.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/__path.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/__signal.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/__string.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/__time.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/compat.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/dirent.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/errno.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/time.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/timers.h: First import - 3.23.10 mit-pthreads/machdep/netbsd-1.1/wait.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/__math.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/__path.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/__signal.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/__string.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/__time.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/compat.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/dirent.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/errno.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/timers.h: First import - 3.23.10 mit-pthreads/machdep/openbsd-2.0/wait.h: First import - 3.23.10 mit-pthreads/machdep/posix-alpha-osf1.h: First import - 3.23.10 mit-pthreads/machdep/posix-bsdi-1.1.h: First import - 3.23.10 mit-pthreads/machdep/posix-bsdi-2.0.h: First import - 3.23.10 mit-pthreads/machdep/posix-freebsd-1.1.h: First import - 3.23.10 mit-pthreads/machdep/posix-freebsd-2.0.h: First import - 3.23.10 mit-pthreads/machdep/posix-hpux-10.20.h: First import - 3.23.10 mit-pthreads/machdep/posix-hpux-9.03.h: First import - 3.23.10 mit-pthreads/machdep/posix-i386-sco-3.2v5.h: First import - 3.23.10 mit-pthreads/machdep/posix-irix-5.2.h: First import - 3.23.10 mit-pthreads/machdep/posix-linux-1.0.h: First import - 3.23.10 mit-pthreads/machdep/posix-netbsd-0.9.h: First import - 3.23.10 mit-pthreads/machdep/posix-netbsd-1.0.h: First import - 3.23.10 mit-pthreads/machdep/posix-netbsd-1.1.h: First import - 3.23.10 mit-pthreads/machdep/posix-openbsd-2.0.h: First import - 3.23.10 mit-pthreads/machdep/posix-romp-bsd.h: First import - 3.23.10 mit-pthreads/machdep/posix-sco-3.2v5.h: First import - 3.23.10 mit-pthreads/machdep/posix-sunos-4.1.3.h: First import - 3.23.10 mit-pthreads/machdep/posix-sunos-5.3.h: First import - 3.23.10 mit-pthreads/machdep/posix-sunos-5.5.h: First import - 3.23.10 mit-pthreads/machdep/posix-ultrix-4.2.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/__math.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/__signal.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/__string.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/__time.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/compat.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/dirent.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/posix/__signal.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/socket.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/syscall.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/timers.h: First import - 3.23.10 mit-pthreads/machdep/sco-3.2v5/trash.can: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/__math.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/__path.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/__signal.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/__string.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/__time.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/cdefs.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/compat.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/dirent.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/fcntlcom.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/signal.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/stat.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/time.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/timers.h: First import - 3.23.10 mit-pthreads/machdep/sunos-4.1.3/wait.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/__math.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/__signal.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/__string.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/__time.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/cdefs.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/compat.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/dirent.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/socket.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/timers.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.3/uio.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/__math.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/__signal.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/__string.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/__time.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/cdefs.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/compat.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/dirent.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/socket.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/timers.h: First import - 3.23.10 mit-pthreads/machdep/sunos-5.5/uio.h: First import - 3.23.10 mit-pthreads/machdep/syscall-alpha-netbsd-1.1.S: First import - 3.23.10 mit-pthreads/machdep/syscall-alpha-netbsd-1.3.S: First import - 3.23.10 mit-pthreads/machdep/syscall-alpha-osf1.S: First import - 3.23.10 mit-pthreads/machdep/syscall-arm32-netbsd-1.3.S: First import - 3.23.10 mit-pthreads/machdep/syscall-hppa-hpux-10.20.S: First import - 3.23.10 mit-pthreads/machdep/syscall-hppa-hpux-9.03.S: First import - 3.23.10 mit-pthreads/machdep/syscall-i386-bsdi-1.1.S: First import - 3.23.10 mit-pthreads/machdep/syscall-i386-bsdi-2.0.S: First import - 3.23.10 mit-pthreads/machdep/syscall-i386-freebsd-1.1.S: First import - 3.23.10 mit-pthreads/machdep/syscall-i386-freebsd-2.0.S: First import - 3.23.10 mit-pthreads/machdep/syscall-i386-linux-1.0.S: First import - 3.23.10 mit-pthreads/machdep/syscall-i386-netbsd-0.9.S: First import - 3.23.10 mit-pthreads/machdep/syscall-i386-netbsd-1.0.S: First import - 3.23.10 mit-pthreads/machdep/syscall-i386-netbsd-1.1.S: First import - 3.23.10 mit-pthreads/machdep/syscall-i386-netbsd-1.3.S: First import - 3.23.10 mit-pthreads/machdep/syscall-i386-openbsd-2.0.S: First import - 3.23.10 mit-pthreads/machdep/syscall-i386-sco-3.2v5.S: First import - 3.23.10 mit-pthreads/machdep/syscall-ip22-irix-5.2.S: First import - 3.23.10 mit-pthreads/machdep/syscall-m68000-netbsd.S: First import - 3.23.10 mit-pthreads/machdep/syscall-r2000-ultrix-4.2.S: First import - 3.23.10 mit-pthreads/machdep/syscall-romp-bsd.S: First import - 3.23.10 mit-pthreads/machdep/syscall-sparc-netbsd-1.1.S: First import - 3.23.10 mit-pthreads/machdep/syscall-sparc-netbsd-1.3.S: First import - 3.23.10 mit-pthreads/machdep/syscall-sparc-sunos-4.1.3.S: First import - 3.23.10 mit-pthreads/machdep/syscall-sparc-sunos-5.3.S: First import - 3.23.10 mit-pthreads/machdep/syscall-sparc-sunos4.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-alpha-netbsd-1.1.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-alpha-netbsd-1.3.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-alpha-osf1.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-arm32-netbsd-1.3.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-hppa-hpux-10.20.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-hppa-hpux-9.03.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-i386-bsdi-2.0.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-i386-freebsd-2.0.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-i386-netbsd-1.1.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-i386-netbsd-1.3.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-i386-netbsd1.0.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-i386-openbsd-2.0.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-i386-sco-3.2v5.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-ip22-irix-5.2.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-m68000-netbsd.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-r2000-ultrix-4.2.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-sparc-netbsd-1.1.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-sparc-netbsd-1.3.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-sparc-sunos-5.3.S: First import - 3.23.10 mit-pthreads/machdep/syscall-template-sparc-sunos4.S: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/__math.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/__signal.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/__stdio.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/__stdlib.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/__string.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/__time.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/__unistd.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/cdefs.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/compat.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/dirent.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/errno.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/time.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/timers.h: First import - 3.23.10 mit-pthreads/machdep/ultrix-4.2/wait.h: First import - 3.23.10 mit-pthreads/machdep/unistd-i386-freebsd-1.1.h: First import - 3.23.10 mit-pthreads/machdep/unistd-i386-linux-1.0.h: First import - 3.23.10 mit-pthreads/machdep/unistd-sparc-sunos-4.1.3.h: First import - 3.23.10 mit-pthreads/net/GNUmakefile.inc: First import - 3.23.10 mit-pthreads/net/gethostbyaddr.c: First import - 3.23.10 mit-pthreads/net/gethostbyname.c: First import - 3.23.10 mit-pthreads/net/gethostent.c: First import - 3.23.10 mit-pthreads/net/getnetbyaddr.c: First import - 3.23.10 mit-pthreads/net/getnetbyname.c: First import - 3.23.10 mit-pthreads/net/getnetent.c: First import - 3.23.10 mit-pthreads/net/getproto.c: First import - 3.23.10 mit-pthreads/net/getprotoent.c: First import - 3.23.10 mit-pthreads/net/getprotoname.c: First import - 3.23.10 mit-pthreads/net/getservbyname.c: First import - 3.23.10 mit-pthreads/net/getservbyport.c: First import - 3.23.10 mit-pthreads/net/getservent.c: First import - 3.23.10 mit-pthreads/net/herror.c: First import - 3.23.10 mit-pthreads/net/inet_addr.c: First import - 3.23.10 mit-pthreads/net/inet_lnaof.c: First import - 3.23.10 mit-pthreads/net/inet_makeaddr.c: First import - 3.23.10 mit-pthreads/net/inet_netof.c: First import - 3.23.10 mit-pthreads/net/inet_network.c: First import - 3.23.10 mit-pthreads/net/inet_ntoa.c: First import - 3.23.10 mit-pthreads/net/net_internal.c: First import - 3.23.10 mit-pthreads/net/net_internal.h: First import - 3.23.10 mit-pthreads/net/proto_internal.c: First import - 3.23.10 mit-pthreads/net/proto_internal.h: First import - 3.23.10 mit-pthreads/net/res_comp.c: First import - 3.23.10 mit-pthreads/net/res_debug.c: First import - 3.23.10 mit-pthreads/net/res_init.c: First import - 3.23.10 mit-pthreads/net/res_internal.c: First import - 3.23.10 mit-pthreads/net/res_internal.h: First import - 3.23.10 mit-pthreads/net/res_mkquery.c: First import - 3.23.10 mit-pthreads/net/res_query.c: First import - 3.23.10 mit-pthreads/net/res_querydomain.c: First import - 3.23.10 mit-pthreads/net/res_search.c: First import - 3.23.10 mit-pthreads/net/res_send.c: First import - 3.23.10 mit-pthreads/net/serv_internal.c: First import - 3.23.10 mit-pthreads/net/serv_internal.h: First import - 3.23.10 mit-pthreads/patches/Streepy.html: First import - 3.23.10 mit-pthreads/patches/Streepy2.html: First import - 3.23.10 mit-pthreads/patches/bill_lear: First import - 3.23.10 mit-pthreads/patches/chris_demetriou: First import - 3.23.10 mit-pthreads/patches/mevans: First import - 3.23.10 mit-pthreads/patches/p153: First import - 3.23.10 mit-pthreads/patches/p155: First import - 3.23.10 mit-pthreads/pg++: First import - 3.23.10 mit-pthreads/pgcc: First import - 3.23.10 mit-pthreads/pthreads/GNUmakefile.inc: First import - 3.23.10 mit-pthreads/pthreads/Makefile.inc: First import - 3.23.10 mit-pthreads/pthreads/_exit.c: First import - 3.23.10 mit-pthreads/pthreads/cleanup.c: First import - 3.23.10 mit-pthreads/pthreads/cond.c: First import - 3.23.10 mit-pthreads/pthreads/condattr.c: First import - 3.23.10 mit-pthreads/pthreads/dump_state.c: First import - 3.23.10 mit-pthreads/pthreads/errno.c: First import - 3.23.10 mit-pthreads/pthreads/fd_pipe.c: First import - 3.23.10 mit-pthreads/pthreads/file.c: First import - 3.23.10 mit-pthreads/pthreads/globals.c: First import - 3.23.10 mit-pthreads/pthreads/info.c: First import - 3.23.10 mit-pthreads/pthreads/init.cc: First import - 3.23.10 mit-pthreads/pthreads/malloc.c: First import - 3.23.10 mit-pthreads/pthreads/mutex.c: First import - 3.23.10 mit-pthreads/pthreads/mutexattr.c: First import - 3.23.10 mit-pthreads/pthreads/panic.c: First import - 3.23.10 mit-pthreads/pthreads/prio_queue.c: First import - 3.23.10 mit-pthreads/pthreads/process.c: First import - 3.23.10 mit-pthreads/pthreads/pthread.c: First import - 3.23.10 mit-pthreads/pthreads/pthread_attr.c: First import - 3.23.10 mit-pthreads/pthreads/pthread_cancel.c: First import - 3.23.10 mit-pthreads/pthreads/pthread_detach.c: First import - 3.23.10 mit-pthreads/pthreads/pthread_init.c: First import - 3.23.10 mit-pthreads/pthreads/pthread_join.c: First import - 3.23.10 mit-pthreads/pthreads/pthread_kill.c: First import - 3.23.10 mit-pthreads/pthreads/pthread_once.c: First import - 3.23.10 mit-pthreads/pthreads/queue.c: First import - 3.23.10 mit-pthreads/pthreads/readv.c: First import - 3.23.10 mit-pthreads/pthreads/schedparam.c: First import - 3.23.10 mit-pthreads/pthreads/select.c: First import - 3.23.10 mit-pthreads/pthreads/sig.c: First import - 3.23.10 mit-pthreads/pthreads/sleep.c: First import - 3.23.10 mit-pthreads/pthreads/specific.c: First import - 3.23.10 mit-pthreads/pthreads/stat.c: First import - 3.23.10 mit-pthreads/pthreads/wait.c: First import - 3.23.10 mit-pthreads/pthreads/writev.c: First import - 3.23.10 mit-pthreads/scripts/GNUmakefile.inc: First import - 3.23.10 mit-pthreads/scripts/Makefile.inc: First import - 3.23.10 mit-pthreads/scripts/pgcc.sh: First import - 3.23.10 mit-pthreads/stdio/GNUmakefile.inc: First import - 3.23.10 mit-pthreads/stdio/Makefile.inc: First import - 3.23.10 mit-pthreads/stdio/README: First import - 3.23.10 mit-pthreads/stdio/clrerr.c: First import - 3.23.10 mit-pthreads/stdio/fclose.c: First import - 3.23.10 mit-pthreads/stdio/fdopen.c: First import - 3.23.10 mit-pthreads/stdio/feof.c: First import - 3.23.10 mit-pthreads/stdio/ferror.c: First import - 3.23.10 mit-pthreads/stdio/fflush.c: First import - 3.23.10 mit-pthreads/stdio/fgetc.c: First import - 3.23.10 mit-pthreads/stdio/fgetline.c: First import - 3.23.10 mit-pthreads/stdio/fgetpos.c: First import - 3.23.10 mit-pthreads/stdio/fgets.c: First import - 3.23.10 mit-pthreads/stdio/fileno.c: First import - 3.23.10 mit-pthreads/stdio/findfp.c: First import - 3.23.10 mit-pthreads/stdio/flags.c: First import - 3.23.10 mit-pthreads/stdio/floatio.h: First import - 3.23.10 mit-pthreads/stdio/fopen.c: First import - 3.23.10 mit-pthreads/stdio/fprintf.c: First import - 3.23.10 mit-pthreads/stdio/fpurge.c: First import - 3.23.10 mit-pthreads/stdio/fputc.c: First import - 3.23.10 mit-pthreads/stdio/fputs.c: First import - 3.23.10 mit-pthreads/stdio/fread.c: First import - 3.23.10 mit-pthreads/stdio/freopen.c: First import - 3.23.10 mit-pthreads/stdio/fscanf.c: First import - 3.23.10 mit-pthreads/stdio/fseek.c: First import - 3.23.10 mit-pthreads/stdio/fsetpos.c: First import - 3.23.10 mit-pthreads/stdio/ftell.c: First import - 3.23.10 mit-pthreads/stdio/funopen.c: First import - 3.23.10 mit-pthreads/stdio/fvwrite.c: First import - 3.23.10 mit-pthreads/stdio/fvwrite.h: First import - 3.23.10 mit-pthreads/stdio/fwalk.c: First import - 3.23.10 mit-pthreads/stdio/fwrite.c: First import - 3.23.10 mit-pthreads/stdio/getc.c: First import - 3.23.10 mit-pthreads/stdio/getc_unlocked.c: First import - 3.23.10 mit-pthreads/stdio/getchar.c: First import - 3.23.10 mit-pthreads/stdio/getchar_unlocked.c: First import - 3.23.10 mit-pthreads/stdio/gets.c: First import - 3.23.10 mit-pthreads/stdio/getw.c: First import - 3.23.10 mit-pthreads/stdio/glue.h: First import - 3.23.10 mit-pthreads/stdio/local.h: First import - 3.23.10 mit-pthreads/stdio/makebuf.c: First import - 3.23.10 mit-pthreads/stdio/mktemp.c: First import - 3.23.10 mit-pthreads/stdio/perror.c: First import - 3.23.10 mit-pthreads/stdio/printf.c: First import - 3.23.10 mit-pthreads/stdio/putc.c: First import - 3.23.10 mit-pthreads/stdio/putc_unlocked.c: First import - 3.23.10 mit-pthreads/stdio/putchar.c: First import - 3.23.10 mit-pthreads/stdio/putchar_unlocked.c: First import - 3.23.10 mit-pthreads/stdio/puts.c: First import - 3.23.10 mit-pthreads/stdio/putw.c: First import - 3.23.10 mit-pthreads/stdio/refill.c: First import - 3.23.10 mit-pthreads/stdio/remove.c: First import - 3.23.10 mit-pthreads/stdio/rewind.c: First import - 3.23.10 mit-pthreads/stdio/rget.c: First import - 3.23.10 mit-pthreads/stdio/scanf.c: First import - 3.23.10 mit-pthreads/stdio/setbuf.c: First import - 3.23.10 mit-pthreads/stdio/setbuffer.c: First import - 3.23.10 mit-pthreads/stdio/setvbuf.c: First import - 3.23.10 mit-pthreads/stdio/snprintf.c: First import - 3.23.10 mit-pthreads/stdio/sprintf.c: First import - 3.23.10 mit-pthreads/stdio/sscanf.c: First import - 3.23.10 mit-pthreads/stdio/stdio.c: First import - 3.23.10 mit-pthreads/stdio/strerror.c: First import - 3.23.10 mit-pthreads/stdio/tempnam.c: First import - 3.23.10 mit-pthreads/stdio/tmpfile.c: First import - 3.23.10 mit-pthreads/stdio/tmpnam.c: First import - 3.23.10 mit-pthreads/stdio/ungetc.c: First import - 3.23.10 mit-pthreads/stdio/vfprintf.c: First import - 3.23.10 mit-pthreads/stdio/vfscanf.c: First import - 3.23.10 mit-pthreads/stdio/vprintf.c: First import - 3.23.10 mit-pthreads/stdio/vscanf.c: First import - 3.23.10 mit-pthreads/stdio/vsnprintf.c: First import - 3.23.10 mit-pthreads/stdio/vsprintf.c: First import - 3.23.10 mit-pthreads/stdio/vsscanf.c: First import - 3.23.10 mit-pthreads/stdio/wbuf.c: First import - 3.23.10 mit-pthreads/stdio/wsetup.c: First import - 3.23.10 mit-pthreads/stdio/xprintf.c: First import - 3.23.10 mit-pthreads/stdlib/GNUmakefile.inc: First import - 3.23.10 mit-pthreads/stdlib/Makefile.inc: First import - 3.23.10 mit-pthreads/stdlib/abort.c: First import - 3.23.10 mit-pthreads/stdlib/atexit.h: First import - 3.23.10 mit-pthreads/stdlib/exit.c: First import - 3.23.10 mit-pthreads/stdlib/rand.c: First import - 3.23.10 mit-pthreads/stdlib/random.c: First import - 3.23.10 mit-pthreads/stdlib/strtod.c: First import - 3.23.10 mit-pthreads/stdlib/strtol.c: First import - 3.23.10 mit-pthreads/stdlib/strtoul.c: First import - 3.23.10 mit-pthreads/stdlib/system.c: First import - 3.23.10 mit-pthreads/string/GNUmakefile.inc: First import - 3.23.10 mit-pthreads/string/Makefile.inc: First import - 3.23.10 mit-pthreads/string/strtok.c: First import - 3.23.10 mit-pthreads/tests/Makefile.in: First import - 3.23.10 mit-pthreads/tests/README: First import - 3.23.10 mit-pthreads/tests/bench_fcntl.c: First import - 3.23.10 mit-pthreads/tests/bench_pipe.c: First import - 3.23.10 mit-pthreads/tests/bench_read.c: First import - 3.23.10 mit-pthreads/tests/p_bench_getpid.c: First import - 3.23.10 mit-pthreads/tests/p_bench_mutex.c: First import - 3.23.10 mit-pthreads/tests/p_bench_pthread_create.c: First import - 3.23.10 mit-pthreads/tests/p_bench_read.c: First import - 3.23.10 mit-pthreads/tests/p_bench_semaphore.c: First import - 3.23.10 mit-pthreads/tests/p_bench_yield.c: First import - 3.23.10 mit-pthreads/tests/test_create.c: First import - 3.23.10 mit-pthreads/tests/test_cwd.c: First import - 3.23.10 mit-pthreads/tests/test_execve.c: First import - 3.23.10 mit-pthreads/tests/test_fcntl.c: First import - 3.23.10 mit-pthreads/tests/test_fork.c: First import - 3.23.10 mit-pthreads/tests/test_netdb.c: First import - 3.23.10 mit-pthreads/tests/test_pause.c: First import - 3.23.10 mit-pthreads/tests/test_preemption.c: First import - 3.23.10 mit-pthreads/tests/test_preemption_float.c: First import - 3.23.10 mit-pthreads/tests/test_pthread_cond_timedwait.c: First import - 3.23.10 mit-pthreads/tests/test_pthread_join.c: First import - 3.23.10 mit-pthreads/tests/test_pthread_mutex.c: First import - 3.23.10 mit-pthreads/tests/test_pw.c: First import - 3.23.10 mit-pthreads/tests/test_readdir.c: First import - 3.23.10 mit-pthreads/tests/test_select.c: First import - 3.23.10 mit-pthreads/tests/test_setjmp.c: First import - 3.23.10 mit-pthreads/tests/test_sleep.c: First import - 3.23.10 mit-pthreads/tests/test_sock_1.c: First import - 3.23.10 mit-pthreads/tests/test_sock_2.c: First import - 3.23.10 mit-pthreads/tests/test_sock_2a.c: First import - 3.23.10 mit-pthreads/tests/test_stdio_1.c: First import - 3.23.10 mit-pthreads/tests/test_switch.c: First import - 3.23.10 mysys/COPYING.LIB: First import - 3.23.10 mysys/getopt.c: First import - 3.23.10 readline/COPYING: First import - 3.23.10 readline/INSTALL: First import - 3.23.10 readline/Makefile.am: First import - 3.23.10 readline/README: First import - 3.23.10 readline/ansi_stdlib.h: First import - 3.23.10 readline/bind.c: First import - 3.23.10 readline/callback.c: First import - 3.23.10 readline/chardefs.h: First import - 3.23.10 readline/configure.in: First import - 3.23.10 readline/configure: First import - 3.23.10 readline/display.c: First import - 3.23.10 readline/emacs_keymap.c: First import - 3.23.10 readline/funmap.c: First import - 3.23.10 readline/histexpand.c: First import - 3.23.10 readline/histfile.c: First import - 3.23.10 readline/histlib.h: First import - 3.23.10 readline/history.c: First import - 3.23.10 readline/history.h: First import - 3.23.10 readline/histsearch.c: First import - 3.23.10 readline/input.c: First import - 3.23.10 readline/isearch.c: First import - 3.23.10 readline/keymaps.c: First import - 3.23.10 readline/keymaps.h: First import - 3.23.10 readline/kill.c: First import - 3.23.10 readline/macro.c: First import - 3.23.10 readline/nls.c: First import - 3.23.10 readline/parens.c: First import - 3.23.10 readline/posixdir.h: First import - 3.23.10 readline/posixjmp.h: First import - 3.23.10 readline/posixstat.h: First import - 3.23.10 readline/readline.c: First import - 3.23.10 readline/readline.h: First import - 3.23.10 readline/rlconf.h: First import - 3.23.10 readline/rldefs.h: First import - 3.23.10 readline/rltty.c: First import - 3.23.10 readline/rltty.h: First import - 3.23.10 readline/rlwinsize.h: First import - 3.23.10 readline/search.c: First import - 3.23.10 readline/shell.c: First import - 3.23.10 readline/signals.c: First import - 3.23.10 readline/tcap.h: First import - 3.23.10 readline/terminal.c: First import - 3.23.10 readline/tilde.c: First import - 3.23.10 readline/tilde.h: First import - 3.23.10 readline/undo.c: First import - 3.23.10 readline/util.c: First import - 3.23.10 readline/vi_keymap.c: First import - 3.23.10 readline/vi_mode.c: First import - 3.23.10 readline/xmalloc.c: First import - 3.23.10 regex/CHANGES: First import - 3.23.10 regex/COPYRIGHT: First import - 3.23.10 regex/README: First import - 3.23.10 regex/WHATSNEW: First import - 3.23.10 regex/cclass.h: First import - 3.23.10 regex/cname.h: First import - 3.23.10 regex/debug.c: First import - 3.23.10 regex/debug.ih: First import - 3.23.10 regex/engine.c: First import - 3.23.10 regex/engine.ih: First import - 3.23.10 regex/main.ih: First import - 3.23.10 regex/regcomp.ih: First import - 3.23.10 regex/regerror.c: First import - 3.23.10 regex/regerror.ih: First import - 3.23.10 regex/regex.3: First import - 3.23.10 regex/regex.7: First import - 3.23.10 regex/regex.h: First import - 3.23.10 regex/regfree.c: First import - 3.23.10 regex/reginit.c: First import - 3.23.10 regex/split.c: First import - 3.23.10 regex/tests: First import - 3.23.10 scripts/msql2mysql.sh: First import - 3.23.10 scripts/mysql_fix_privilege_tables.sh: First import - 3.23.10 scripts/mysql_setpermission.sh: First import - 3.23.10 scripts/mysqlaccess.conf: First import - 3.23.10 scripts/mysqlbug.sh: First import - 3.23.10 sql-bench/Data/ATIS/aircraft.txt: First import - 3.23.10 sql-bench/Data/ATIS/airline.txt: First import - 3.23.10 sql-bench/Data/ATIS/airport.txt: First import - 3.23.10 sql-bench/Data/ATIS/airport_service.txt: First import - 3.23.10 sql-bench/Data/ATIS/city.txt: First import - 3.23.10 sql-bench/Data/ATIS/class_of_service.txt: First import - 3.23.10 sql-bench/Data/ATIS/code_description.txt: First import - 3.23.10 sql-bench/Data/ATIS/compound_class.txt: First import - 3.23.10 sql-bench/Data/ATIS/connect_leg.txt: First import - 3.23.10 sql-bench/Data/ATIS/connection.txt: First import - 3.23.10 sql-bench/Data/ATIS/date_day.txt: First import - 3.23.10 sql-bench/Data/ATIS/day_name.txt: First import - 3.23.10 sql-bench/Data/ATIS/dual_carrier.txt: First import - 3.23.10 sql-bench/Data/ATIS/fare.txt: First import - 3.23.10 sql-bench/Data/ATIS/flight.txt: First import - 3.23.10 sql-bench/Data/ATIS/flight_class.txt: First import - 3.23.10 sql-bench/Data/ATIS/flight_day.txt: First import - 3.23.10 sql-bench/Data/ATIS/flight_fare.txt: First import - 3.23.10 sql-bench/Data/ATIS/food_service.txt: First import - 3.23.10 sql-bench/Data/ATIS/ground_service.txt: First import - 3.23.10 sql-bench/Data/ATIS/month_name.txt: First import - 3.23.10 sql-bench/Data/ATIS/restrict_carrier.txt: First import - 3.23.10 sql-bench/Data/ATIS/restrict_class.txt: First import - 3.23.10 sql-bench/Data/ATIS/restriction.txt: First import - 3.23.10 sql-bench/Data/ATIS/state.txt: First import - 3.23.10 sql-bench/Data/ATIS/stop.txt: First import - 3.23.10 sql-bench/Data/ATIS/stop1.txt: First import - 3.23.10 sql-bench/Data/ATIS/time_interval.txt: First import - 3.23.10 sql-bench/Data/ATIS/time_zone.txt: First import - 3.23.10 sql-bench/Data/ATIS/transport.txt: First import - 3.23.10 sql-bench/Data/Wisconsin/onek.data: First import - 3.23.10 sql-bench/Data/Wisconsin/tenk.data: First import - 3.23.10 sql-bench/README: First import - 3.23.10 sql-bench/Results/ATIS-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/ATIS-AdabasD-Linux_2.0.35_i686-cmp-adabasd,mysql: First import - 3.23.10 sql-bench/Results/ATIS-msql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/ATIS-mysql-3.21-Linux_2.2.1_i686: First import - 3.23.10 sql-bench/Results/ATIS-mysql-HP_UX_B.10.20_9000_778: First import - 3.23.10 sql-bench/Results/ATIS-mysql-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/ATIS-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/ATIS-mysql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/ATIS-mysql-Linux_2.2.10_i686: First import - 3.23.10 sql-bench/Results/ATIS-mysql-Linux_2.2.1_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/ATIS-mysql-SunOS_5.5.1_sun4u: First import - 3.23.10 sql-bench/Results/ATIS-mysql-SunOS_5.6_sun4m: ***MISSING WEAVE*** sql-bench/Results/ATIS-mysql-SunOS_5.7_sun4m: First import - 3.23.10 sql-bench/Results/ATIS-mysql-SunOS_5.7_sun4u: First import - 3.23.10 sql-bench/Results/ATIS-mysql_3.21-Linux_2.0.35_i686: First import - 3.23.10 sql-bench/Results/ATIS-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/ATIS-mysql_odbc-win98: First import - 3.23.10 sql-bench/Results/ATIS-oracle-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/ATIS-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/ATIS-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/ATIS-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/ATIS-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/RUN-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/RUN-msql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/RUN-mysql-3.21-Linux_2.2.1_i686: First import - 3.23.10 sql-bench/Results/RUN-mysql-HP_UX_B.10.20_9000_778: First import - 3.23.10 sql-bench/Results/RUN-mysql-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/RUN-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/RUN-mysql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/RUN-mysql-Linux_2.2.10_i686: First import - 3.23.10 sql-bench/Results/RUN-mysql-Linux_2.2.1_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/RUN-mysql-SunOS_5.5.1_sun4u: First import - 3.23.10 sql-bench/Results/RUN-mysql-SunOS_5.6_sun4m: ***MISSING WEAVE*** sql-bench/Results/RUN-mysql-SunOS_5.7_sun4m: First import - 3.23.10 sql-bench/Results/RUN-mysql-SunOS_5.7_sun4u: First import - 3.23.10 sql-bench/Results/RUN-mysql_3.21-Linux_2.0.35_i686: First import - 3.23.10 sql-bench/Results/RUN-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/RUN-mysql_odbc-win98: First import - 3.23.10 sql-bench/Results/RUN-oracle-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/RUN-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/RUN-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/RUN-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/RUN-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/alter-table-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/alter-table-AdabasD-Linux_2.0.35_i686-cmp-adabasd,mysql: First import - 3.23.10 sql-bench/Results/alter-table-msql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/alter-table-mysql-3.21-Linux_2.2.1_i686: First import - 3.23.10 sql-bench/Results/alter-table-mysql-HP_UX_B.10.20_9000_778: First import - 3.23.10 sql-bench/Results/alter-table-mysql-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/alter-table-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/alter-table-mysql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/alter-table-mysql-Linux_2.2.10_i686: First import - 3.23.10 sql-bench/Results/alter-table-mysql-Linux_2.2.1_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/alter-table-mysql-SunOS_5.5.1_sun4u: First import - 3.23.10 sql-bench/Results/alter-table-mysql-SunOS_5.6_sun4m: ***MISSING WEAVE*** sql-bench/Results/alter-table-mysql-SunOS_5.7_sun4m: First import - 3.23.10 sql-bench/Results/alter-table-mysql-SunOS_5.7_sun4u: First import - 3.23.10 sql-bench/Results/alter-table-mysql_3.21-Linux_2.0.35_i686: First import - 3.23.10 sql-bench/Results/alter-table-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/alter-table-mysql_odbc-win98: First import - 3.23.10 sql-bench/Results/alter-table-oracle-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/alter-table-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/alter-table-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/alter-table-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/alter-table-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/big-tables-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/big-tables-msql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/big-tables-mysql-3.21-Linux_2.2.1_i686: First import - 3.23.10 sql-bench/Results/big-tables-mysql-HP_UX_B.10.20_9000_778: First import - 3.23.10 sql-bench/Results/big-tables-mysql-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/big-tables-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/big-tables-mysql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/big-tables-mysql-Linux_2.2.10_i686: First import - 3.23.10 sql-bench/Results/big-tables-mysql-Linux_2.2.1_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/big-tables-mysql-SunOS_5.5.1_sun4u: First import - 3.23.10 sql-bench/Results/big-tables-mysql-SunOS_5.6_sun4m: ***MISSING WEAVE*** sql-bench/Results/big-tables-mysql-SunOS_5.7_sun4m: First import - 3.23.10 sql-bench/Results/big-tables-mysql-SunOS_5.7_sun4u: First import - 3.23.10 sql-bench/Results/big-tables-mysql_3.21-Linux_2.0.35_i686: First import - 3.23.10 sql-bench/Results/big-tables-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/big-tables-mysql_odbc-win98: First import - 3.23.10 sql-bench/Results/big-tables-oracle-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/big-tables-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/big-tables-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/big-tables-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/big-tables-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/connect-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/connect-msql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/connect-mysql-3.21-Linux_2.2.1_i686: First import - 3.23.10 sql-bench/Results/connect-mysql-HP_UX_B.10.20_9000_778: First import - 3.23.10 sql-bench/Results/connect-mysql-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/connect-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/connect-mysql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/connect-mysql-Linux_2.2.10_i686: First import - 3.23.10 sql-bench/Results/connect-mysql-Linux_2.2.1_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/connect-mysql-SunOS_5.5.1_sun4u: First import - 3.23.10 sql-bench/Results/connect-mysql-SunOS_5.6_sun4m: ***MISSING WEAVE*** sql-bench/Results/connect-mysql-SunOS_5.7_sun4m: First import - 3.23.10 sql-bench/Results/connect-mysql-SunOS_5.7_sun4u: First import - 3.23.10 sql-bench/Results/connect-mysql_3.21-Linux_2.0.35_i686: First import - 3.23.10 sql-bench/Results/connect-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/connect-mysql_odbc-win98: First import - 3.23.10 sql-bench/Results/connect-oracle-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/connect-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/connect-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/connect-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/create-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/create-msql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/create-mysql-3.21-Linux_2.2.1_i686: First import - 3.23.10 sql-bench/Results/create-mysql-HP_UX_B.10.20_9000_778: First import - 3.23.10 sql-bench/Results/create-mysql-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/create-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/create-mysql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/create-mysql-Linux_2.2.10_i686: First import - 3.23.10 sql-bench/Results/create-mysql-Linux_2.2.1_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/create-mysql-SunOS_5.5.1_sun4u: First import - 3.23.10 sql-bench/Results/create-mysql-SunOS_5.6_sun4m: ***MISSING WEAVE*** sql-bench/Results/create-mysql-SunOS_5.7_sun4m: First import - 3.23.10 sql-bench/Results/create-mysql-SunOS_5.7_sun4u: First import - 3.23.10 sql-bench/Results/create-mysql_3.21-Linux_2.0.35_i686: First import - 3.23.10 sql-bench/Results/create-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/create-mysql_odbc-win98: First import - 3.23.10 sql-bench/Results/create-oracle-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/create-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/create-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/create-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/insert-mysql-HP_UX_B.10.20_9000_778: First import - 3.23.10 sql-bench/Results/select-mysql-HP_UX_B.10.20_9000_778: First import - 3.23.10 sql-bench/Results/wisconsin-mysql-HP_UX_B.10.20_9000_778: First import - 3.23.10 sql/md5.c: First import - 3.23.10 sql/share/norwegian-ny/.cvsignore: First import - 3.23.10 sql/share/norwegian/.cvsignore: First import - 3.23.10 stamp-h.in: First import - 3.23.10 strings/ChangeLog: First import - 3.23.10 strings/bfill.c: First import - 3.23.10 strings/bmove.c: First import - 3.23.10 strings/strend.c: First import - 3.23.10 strings/strstr.c: First import - 3.23.10 strings/strxnmov.c: First import - 3.23.10 tests/auto_increment.res: First import - 3.23.10 tests/auto_increment.tst: First import - 3.23.10 tests/function.res: First import - 3.23.10 tests/function.tst: First import - 3.23.10 tests/grant.res: First import - 3.23.10 tests/lock_test.res: First import - 3.23.10 tests/table_types.pl: First import - 3.23.10 tests/udf_test.res: First import - 3.23.10 tests/udf_test: First import - 3.23.10 sql-bench/Results-linux/ATIS-mysql-Linux_2.0.33_i586-cmp-access,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/ATIS-mysql-Linux_2.0.33_i586-cmp-ms-sql,mysql,sybase: ***MISSING WEAVE*** sql-bench/Results-linux/RUN-mysql-Linux_2.0.33_i586-cmp-access,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/RUN-mysql-Linux_2.0.33_i586-cmp-ms-sql,mysql,sybase: ***MISSING WEAVE*** sql-bench/Results-linux/big-tables-mysql-Linux_2.0.33_i586-cmp-access,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/big-tables-mysql-Linux_2.0.33_i586-cmp-ms-sql,mysql,sybase: ***MISSING WEAVE*** sql-bench/Results-linux/connect-mysql-Linux_2.0.33_i586-cmp-access,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/connect-mysql-Linux_2.0.33_i586-cmp-ms-sql,mysql,sybase: ***MISSING WEAVE*** sql-bench/Results-linux/create-mysql-Linux_2.0.33_i586-cmp-access,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/create-mysql-Linux_2.0.33_i586-cmp-ms-sql,mysql,sybase: ***MISSING WEAVE*** sql-bench/Results-linux/insert-mysql-Linux_2.0.33_i586-cmp-access,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/insert-mysql-Linux_2.0.33_i586-cmp-ms-sql,mysql,sybase: ***MISSING WEAVE*** sql-bench/Results-linux/select-mysql-Linux_2.0.33_i586-cmp-access,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/select-mysql-Linux_2.0.33_i586-cmp-ms-sql,mysql,sybase: ***MISSING WEAVE*** sql-bench/Results-linux/wisconsin-mysql-Linux_2.0.33_i586-cmp-access,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/wisconsin-mysql-Linux_2.0.33_i586-cmp-ms-sql,mysql,sybase: ***MISSING WEAVE*** sql-bench/Results-win32/ATIS-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/ATIS-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/ATIS-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/ATIS-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/ATIS-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/ATIS-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/ATIS-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/ATIS-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/RUN-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/RUN-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/RUN-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/RUN-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/RUN-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/RUN-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/RUN-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/RUN-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/alter-table-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/alter-table-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/alter-table-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/alter-table-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/alter-table-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/alter-table-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/alter-table-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/alter-table-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/big-tables-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/big-tables-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/big-tables-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/big-tables-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/big-tables-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/big-tables-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/big-tables-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/big-tables-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/connect-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/connect-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/connect-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/connect-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/connect-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/connect-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/connect-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/connect-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/create-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/create-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/create-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/create-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/create-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/create-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/create-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/create-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/insert-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/insert-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/insert-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/insert-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/insert-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/insert-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/insert-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/insert-sybase_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/select-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/select-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/select-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/select-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/select-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/select-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/select-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/wisconsin-db2_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/wisconsin-informix_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/wisconsin-ms-sql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/wisconsin-mysql-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/wisconsin-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/wisconsin-oracle_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results-win32/wisconsin-solid_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase: First import - 3.23.10 sql-bench/Results/create-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/insert-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/insert-msql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/insert-mysql-3.21-Linux_2.2.1_i686: First import - 3.23.10 sql-bench/Results/insert-mysql-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/insert-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/insert-mysql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/insert-mysql-Linux_2.2.10_i686: First import - 3.23.10 sql-bench/Results/insert-mysql-Linux_2.2.1_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/insert-mysql-SunOS_5.5.1_sun4u: First import - 3.23.10 sql-bench/Results/insert-mysql-SunOS_5.6_sun4m: ***MISSING WEAVE*** sql-bench/Results/insert-mysql-SunOS_5.7_sun4m: First import - 3.23.10 sql-bench/Results/insert-mysql-SunOS_5.7_sun4u: First import - 3.23.10 sql-bench/Results/insert-mysql_3.21-Linux_2.0.35_i686: First import - 3.23.10 sql-bench/Results/insert-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/insert-mysql_odbc-win98: First import - 3.23.10 sql-bench/Results/insert-oracle-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/insert-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/insert-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/insert-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/insert-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/select-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/select-msql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/select-mysql-3.21-Linux_2.2.1_i686: First import - 3.23.10 sql-bench/Results/select-mysql-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/select-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/select-mysql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/select-mysql-Linux_2.2.10_i686: First import - 3.23.10 sql-bench/Results/select-mysql-Linux_2.2.1_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/select-mysql-SunOS_5.5.1_sun4u: First import - 3.23.10 sql-bench/Results/select-mysql-SunOS_5.6_sun4m: ***MISSING WEAVE*** sql-bench/Results/select-mysql-SunOS_5.7_sun4m: First import - 3.23.10 sql-bench/Results/select-mysql-SunOS_5.7_sun4u: First import - 3.23.10 sql-bench/Results/select-mysql_3.21-Linux_2.0.35_i686: First import - 3.23.10 sql-bench/Results/select-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/select-mysql_odbc-win98: First import - 3.23.10 sql-bench/Results/select-oracle-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/select-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/select-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/select-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/select-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/wisconsin-Adabas-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/wisconsin-msql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/wisconsin-mysql-3.21-Linux_2.2.1_i686: First import - 3.23.10 sql-bench/Results/wisconsin-mysql-Linux_2.0.35_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/wisconsin-mysql-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/wisconsin-mysql-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/wisconsin-mysql-Linux_2.2.10_i686: First import - 3.23.10 sql-bench/Results/wisconsin-mysql-Linux_2.2.1_i686-cmp-adabas,mysql: First import - 3.23.10 sql-bench/Results/wisconsin-mysql-SunOS_5.5.1_sun4u: First import - 3.23.10 sql-bench/Results/wisconsin-mysql-SunOS_5.6_sun4m: ***MISSING WEAVE*** sql-bench/Results/wisconsin-mysql-SunOS_5.7_sun4m: First import - 3.23.10 sql-bench/Results/wisconsin-mysql-SunOS_5.7_sun4u: First import - 3.23.10 sql-bench/Results/wisconsin-mysql_3.21-Linux_2.0.35_i686: First import - 3.23.10 sql-bench/Results/wisconsin-mysql_fast-Linux_2.2.10_i686-cmp-msql,mysql: First import - 3.23.10 sql-bench/Results/wisconsin-mysql_odbc-win98: First import - 3.23.10 sql-bench/Results/wisconsin-oracle-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/wisconsin-oracle_fast-Linux_2.0.36_i686-cmp-mysql,oracle: First import - 3.23.10 sql-bench/Results/wisconsin-pg-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/wisconsin-pg_fast-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/Results/wisconsin-solid-Linux_2.0.36_i686-cmp-mysql,pg,solid: First import - 3.23.10 sql-bench/limits/Adabas.cfg: First import - 3.23.10 sql-bench/limits/Adabas.comment: First import - 3.23.10 sql-bench/limits/Informix.cfg: First import - 3.23.10 sql-bench/limits/Informix.comment: First import - 3.23.10 sql-bench/limits/access.comment: First import - 3.23.10 sql-bench/limits/access_odbc.cfg: First import - 3.23.10 sql-bench/limits/db2.cfg: First import - 3.23.10 sql-bench/limits/empress.cfg: First import - 3.23.10 sql-bench/limits/empress.comment: First import - 3.23.10 sql-bench/limits/ms-sql65.cfg: First import - 3.23.10 sql-bench/limits/msql.cfg: First import - 3.23.10 sql-bench/limits/mysql-3.22.cfg: First import - 3.23.10 sql-bench/limits/pg.comment: First import - 3.23.10 sql-bench/limits/solid-nt4.cfg: First import - 3.23.10 sql-bench/limits/solid.cfg: First import - 3.23.10 sql-bench/limits/sybase.cfg: First import - 3.23.10 support-files/binary-configure.sh: First import - 3.23.10 support-files/mysql-log-rotate.sh: First import - 3.23.10 mkinstalldirs: Update to 3.23.11 Docs/mysqld_error.txt: Update to 3.23.11 man/mysql.1: Update to 3.23.11 mysys/ChangeLog: Update to 3.23.11 scripts/mysqlaccess.sh: Update to 3.23.11 strings/Attic/ptr_cmp.c: Update to 3.23.11 dbug/dbug_analyze.c: Update for 3.23.12 dbug/doinstall.sh: Update for 3.23.12 dbug/install.sh: Update for 3.23.12 dbug/mklintlib.sh: Update for 3.23.12 dbug/qmake.cmd: Update for 3.23.12 dbug/vargs.h: Update for 3.23.12 isam/test_all.res: Update for 3.23.12 isam/test_all: Update for 3.23.12 myisam/NEWS: Update for 3.23.12 myisam/common_words: ***MISSING WEAVE*** myisam/mi_test_all.res: Update for 3.23.12 myisam/test_pack: Update for 3.23.12 scripts/safe_mysqld-watch.sh: Update for 3.23.12 sql/ha_hash.h: Update for 3.23.12 sql/nt_servc.h: Update for 3.23.12 strings/READ-ME: Update for 3.23.12 strings/bzero.c: Update for 3.23.12 strings/latin2.def: Update for 3.23.12 strings/memset.c: Update for 3.23.12 strings/strcat.c: Update for 3.23.12 strings/strchr.c: Update for 3.23.12 strings/strcmp.c: Update for 3.23.12 strings/string.doc: Update for 3.23.12 strings/strings-not-used.h: Update for 3.23.12 strings/strlen.c: Update for 3.23.12 strings/strrchr.c: Update for 3.23.12 strings/t_ctype.h: Update for 3.23.12 Build-tools/Do-create-perl-rpms: Initial checkin of MySQL build environment. Build-tools/Do-local-patch-file: Initial checkin of MySQL build environment. Build-tools/newest: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-01.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-02.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-03.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-04.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-05.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-06.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-07.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-08.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-09.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-10.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-11.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-12.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-13.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-14.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-15.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-16.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-17.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql-compatible.jpg: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql_anim-01.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql_anim-02.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql_anim-03.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql_anim-04.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql_anim-05.gif: Initial checkin of MySQL build environment. Docs/MySQL-logos/mysql_anim-06.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/afghanistan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/albania.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/algeria.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/andorra.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/angola.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/antartica.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/antigua-and-barbuda.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/argentina.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/armenia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/australia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/austria.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/azerbaijan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/bahamas.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/bahrein.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/bangladesh.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/barbados.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/belarus.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/belgium.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/belize.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/benin.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/bermuda.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/bhutan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/bolivia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/bosnia-and-herzegovina.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/botswana.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/brazil.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/brunei.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/bulgaria.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/burkina-faso.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/burma.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/burundi.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/cambodia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/cameroon.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/canada.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/cape-verde.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/central-african-republic.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/chad.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/chile.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/china.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/colombia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/comoros.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/congo.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/costa-rica.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/cote-d-ivoire.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/croatia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/cuba.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/cyprus.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/czech-republic.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/denmark-original-incorrect.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/denmark.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/djibouti.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/dominica.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/dominican-republic.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/ecuador.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/egypt.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/el-salvador.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/equatorial-guinea.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/eritrea.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/estonia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/ethiopia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/fiji.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/finland.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/france.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/gabon.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/gambia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/georgia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/germany.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/ghana.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/great-britain.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/greece.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/greenland.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/grenada.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/guatemala.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/guinea-bissau.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/guinea.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/guyana.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/haiti.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/honduras.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/hungary.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/iceland.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/india.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/indonesia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/iran.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/iraq.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/ireland.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/israel.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/italy.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/jamaica.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/japan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/jordan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/kazakhstan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/kenya.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/kiribati.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/kuwait.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/kyrgyzstan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/laos.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/latvia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/lebanon.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/lesotho.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/liberia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/libya.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/liechtenstein.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/lithuania.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/luxembourg.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/macedonia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/madagascar.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/malawi.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/malaysia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/maldives.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/mali.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/malta.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/marshall.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/mauritania.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/mauritius.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/mexico.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/micronesia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/moldova.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/monaco.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/mongolia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/morocco.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/mozambique.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/namibia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/nauru.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/nepal.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/netherlands.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/new-zealand.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/nicaragua.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/niger.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/nigeria.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/north-korea.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/norway.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/oman.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/pakistan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/panama.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/papua-new-guinea.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/paraguay.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/peru.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/philippines.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/poland.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/portugal.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/qatar.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/romania.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/russia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/rwanda.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/saint-kitts-and-nevis.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/saint-lucia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/samoa.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/sao-tome-and-principe.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/saudi-arabia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/senegal.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/seychelles.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/sierra-leone.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/singapore.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/slovakia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/slovenia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/solomon-islands.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/somalia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/south-africa.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/south-korea.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/spain.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/sri-lanka.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/sudan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/suriname.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/swaziland.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/sweden.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/sweden2.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/switzerland.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/syria.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/taiwan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/tajikistan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/tanzania.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/thailand.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/togo.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/tonga.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/trinidad-and-tobago.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/tunisia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/turkey.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/turkmenistan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/tuvalu.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/uganda.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/ukraine.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/united-arab-emirates.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/united-states-of-america.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/uruguay.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/usa.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/uzbekistan.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/vanuatu.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/venezuela.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/vietnam.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/vincent-and-grenadines.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/yemen.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/yugoslavia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/zaire.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/zambia.gif: Initial checkin of MySQL build environment. Docs/Raw-Flags/zimbabwe.gif: Initial checkin of MySQL build environment. Docs/Support/generate-flag-images: Initial checkin of MySQL build environment. Docs/Support/generate-mirror-listing.pl: Initial checkin of MySQL build environment. Docs/Support/generate-text-files.pl: Initial checkin of MySQL build environment. Docs/Support/make-makefile: Initial checkin of MySQL build environment. Docs/Support/texinfo.tex: Initial checkin of MySQL build environment. Docs/Translations/myodbc-br.texi: Initial checkin of MySQL build environment. man/.cvsignore: Initial checkin of MySQL build environment. mit-pthreads/include/pthread/config.h: Initial checkin of MySQL build environment. readline/.cvsignore: Initial checkin of MySQL build environment. sql/share/.cvsignore: Initial checkin of MySQL build environment. tests/.cvsignore: Initial checkin of MySQL build environment. libmysql/acconfig.h: ***MISSING WEAVE*** libmysql/acinclude.m4: Configure stuff for libmysql. libmysql/configure.in: Configure stuff for libmysql. mit-pthreads/.cvsignore: More work on initial build mit-pthreads/include/pthread/cond.h: Update to 3.23.12 mit-pthreads/machdep/engine-i386-linux-2.0.c: Update to 3.23.12 mit-pthreads/machdep/engine-i386-linux-2.0.h: Update to 3.23.12 mit-pthreads/machdep/posix-linux-2.0.h: Update to 3.23.12 mit-pthreads/machdep/unistd-i386-linux-2.0.h: Update to 3.23.12 sql/add_errmsg: Update to 3.23.12 sql/watchdog_mysqld: Update to 3.23.12 strings/Attic/memory.h: Update to 3.23.12 dbug/.cvsignore: Update to 3.23.12 heap/.cvsignore: Update to 3.23.12 merge/.cvsignore: Update to 3.23.12 mit-pthreads/bin/.cvsignore: Update to 3.23.12 mit-pthreads/bin/finger/.cvsignore: Update to 3.23.12 mit-pthreads/lib/.cvsignore: Update to 3.23.12 mit-pthreads/lib/libpthreadutil/.cvsignore: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/__math.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/__path.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/__signal.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/__stdio.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/__stdlib.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/__string.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/__time.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/cdefs.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/compat.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/dirent.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/errno.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/socket.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/socketcall.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/timers.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/uio.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/wait.h: Update to 3.23.12 mit-pthreads/tests/.cvsignore: Update to 3.23.12 myisammrg/.cvsignore: Update to 3.23.12 regex/.cvsignore: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/extra/bits/local_lim.h: Update to 3.23.12 mit-pthreads/machdep/linux-2.0/extra/bits/socket.h: Update to 3.23.12 vio/.cvsignore: Update for 3.23.12 vio/Vio.cc: Update for 3.23.12 vio/VioAcceptorFd.cc: Update for 3.23.12 vio/VioAcceptorFd.h: Update for 3.23.12 vio/VioConnectorFd.cc: Update for 3.23.12 vio/VioConnectorFd.h: Update for 3.23.12 vio/VioFd.cc: Update for 3.23.12 vio/VioFd.h: Update for 3.23.12 vio/VioPipe.cc: Update for 3.23.12 vio/VioSSL.cc: Update for 3.23.12 vio/VioSSL.h: Update for 3.23.12 vio/VioSSLAcceptorFd.cc: Update for 3.23.12 vio/VioSSLFactoriesFd.cc: Update for 3.23.12 vio/VioSSLFactoriesFd.h: Update for 3.23.12 vio/VioSocket.cc: Update for 3.23.12 vio/VioSocket.h: Update for 3.23.12 vio/version.cc: Update for 3.23.12 vio/vio-global.h: Update for 3.23.12 vio/vioelitexx.cc: Update for 3.23.12 vio/viotest-ssl.cc: Update for 3.23.12 vio/viotest-sslconnect.cc: Update for 3.23.12 vio/viotest.cc: Update for 3.23.12 vio/viotypes.h: Update for 3.23.12 strings/strxmov.c: Update to 3.23.12a sql/md5.h: Lots of patches for Alpha-Linux Docs/Images/empty.png: *** empty log message *** Docs/Images/flag-background.pnm: *** empty log message *** NEW-RPMS/.cvsignore: Changes for new build environment sql-bench/example.bat: Update for 3.23.12a sql-bench/pwd.bat: Update for 3.23.12a sql-bench/uname.bat: Update for 3.23.12a sql-bench/Results/Attic/ATIS-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results/Attic/RUN-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results/Attic/alter-table-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results/Attic/big-tables-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results/Attic/connect-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results/Attic/create-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results/Attic/insert-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results/Attic/select-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results/Attic/wisconsin-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results-linux/ATIS-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/ATIS-mysql-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/ATIS-mysql-Linux_dynamic: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/ATIS-mysql-Linux_pgcc: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/ATIS-mysql-Linux_static: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/ATIS-mysql_fast-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/ATIS-mysql_local_tcp-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/ATIS-mysql_new-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/RUN-mysql-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/RUN-mysql-Linux_dynamic: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/RUN-mysql-Linux_pgcc: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/RUN-mysql-Linux_static: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/RUN-mysql_fast-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/RUN-mysql_local_tcp-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/RUN-mysql_new-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/big-tables-mysql-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/big-tables-mysql-Linux_dynamic: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/big-tables-mysql-Linux_pgcc: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/big-tables-mysql-Linux_static: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/big-tables-mysql_fast-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/big-tables-mysql_local_tcp-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/big-tables-mysql_new-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/connect-mysql-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/connect-mysql-Linux_dynamic: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/connect-mysql-Linux_pgcc: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/connect-mysql-Linux_static: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/connect-mysql_fast-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/connect-mysql_local_tcp-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/connect-mysql_new-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/create-mysql-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/create-mysql-Linux_dynamic: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/create-mysql-Linux_pgcc: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/create-mysql-Linux_static: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/create-mysql_fast-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/create-mysql_local_tcp-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/create-mysql_new-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/insert-mysql-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/insert-mysql-Linux_dynamic: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/insert-mysql-Linux_pgcc: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/insert-mysql-Linux_static: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/insert-mysql_fast-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/insert-mysql_local_tcp-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/insert-mysql_new-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/select-mysql-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/select-mysql-Linux_dynamic: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/select-mysql-Linux_pgcc: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/select-mysql-Linux_static: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/select-mysql_fast-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/select-mysql_local_tcp-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/select-mysql_new-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/wisconsin-mysql-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/wisconsin-mysql-Linux_dynamic: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/wisconsin-mysql-Linux_pgcc: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/wisconsin-mysql-Linux_static: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/wisconsin-mysql_fast-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/wisconsin-mysql_local_tcp-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/Attic/wisconsin-mysql_new-Linux_2.0.33_i586: ***MISSING WEAVE*** sql-bench/Results-linux/alter-table-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results-linux/big-tables-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results-linux/connect-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results-linux/insert-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results-linux/select-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results-linux/wisconsin-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/.cvsignore: Update of benchmarks sql-bench/Results-win32/ATIS-access_odbc-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/ATIS-mysql-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/RUN-access_odbc-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/RUN-mysql-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/alter-table-access_odbc-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/alter-table-mysql-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/big-tables-access_odbc-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/big-tables-mysql-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/connect-access_odbc-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/connect-mysql-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/create-access_odbc-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/create-mysql-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/insert-access_odbc-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/insert-mysql-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/select-access_odbc-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/select-mysql-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/wisconsin-access_odbc-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-win32/wisconsin-mysql-win98-cmp-access,mysql: Update of benchmarks sql-bench/Results-linux/RUN-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** sql-bench/Results-linux/create-mysql-Linux_2.2.12_20smp_i686: ***MISSING WEAVE*** Docs/Images/Attic/mysql5.gif: Second copy Docs/Images/Attic/html-fs.gif: Moved to web...icons Docs/Images/Attic/mysql-01.gif: Moved to web...icons Docs/Images/Attic/mysql-02.gif: Moved to web...icons Docs/Images/Attic/mysql-03.gif: Moved to web...icons Docs/Images/Attic/mysql-04.gif: Moved to web...icons Docs/Images/Attic/mysql-05.gif: Moved to web...icons Docs/Images/Attic/mysql-06.gif: Moved to web...icons Docs/Images/Attic/mysql-07.gif: Moved to web...icons Docs/Images/Attic/mysql-08.gif: Moved to web...icons Docs/Images/Attic/mysql-09.gif: Moved to web...icons Docs/Images/Attic/mysql-10.gif: Moved to web...icons Docs/Images/Attic/mysql-11.gif: Moved to web...icons Docs/Images/Attic/mysql-12.gif: Moved to web...icons Docs/Images/Attic/mysql-13.gif: Moved to web...icons Docs/Images/Attic/mysql-14.gif: Moved to web...icons Docs/Images/Attic/mysql-15.gif: Moved to web...icons Docs/Images/Attic/mysql-16.gif: Moved to web...icons Docs/Images/Attic/mysql-17.gif: Moved to web...icons Docs/Images/Attic/mysql-18.gif: Moved to web...icons Docs/Images/Attic/mysql-19.gif: Moved to web...icons Docs/Images/Attic/mysql-compatible.jpg: Moved to web...icons Docs/Images/Attic/mysql_anim-01.gif: Moved to web...icons Docs/Images/Attic/mysql_anim-02.gif: Moved to web...icons Docs/Images/Attic/mysql_anim-03.gif: Moved to web...icons Docs/Images/Attic/mysql_anim-04.gif: Moved to web...icons Docs/Images/Attic/mysql_anim-05.gif: Moved to web...icons Docs/Images/Attic/mysql_anim-06.gif: Moved to web...icons Docs/Images/Attic/powered-by-MySQL-transparent.gif: Moved to web...icons scripts/mysql_zap.sh: Fixes from the Debian maintainer Build-tools/Do-patch-file: Update at work myisam/TODO: Fixes for raid + other things regex/utils.h: Renamed some portability defines heap/make-ccc: First version isam/make-ccc: First version merge/make-ccc: First version myisam/make-ccc: First version myisammrg/make-ccc: First version mysys/make-ccc: First version regex/make-ccc: First version strings/make-ccc: First version sql/share/romanian/errmsg.sys: ***MISSING WEAVE*** Docs/manual-license-spanish.texi: Update to 3.23.13 BUILD/test-alpha-ccc: Bug patches from mailing list sql-bench/Results-win32/ATIS-mysql-win98: Bug patches from mailing list sql-bench/Results-win32/RUN-mysql-win98: Bug patches from mailing list sql-bench/Results-win32/alter-table-mysql-win98: Bug patches from mailing list sql-bench/Results-win32/big-tables-mysql-win98: Bug patches from mailing list sql-bench/Results-win32/connect-mysql-win98: Bug patches from mailing list sql-bench/Results-win32/create-mysql-win98: Bug patches from mailing list sql-bench/Results-win32/insert-mysql-win98: Bug patches from mailing list sql-bench/Results-win32/select-mysql-win98: Bug patches from mailing list sql-bench/Results-win32/wisconsin-mysql-win98: Bug patches from mailing list mit-pthreads/Changes-mysql: Updated for Linux mit-pthreads/config/config.h.in: Updated for Linux mit-pthreads/config/configure.in: Updated for Linux mit-pthreads/config/configure: Updated for Linux mit-pthreads/gen/ttyname.c: Updated for Linux mit-pthreads/machdep/syscall-i386-linux-2.0.S: Updated for Linux mit-pthreads/machdep/linux-2.0/__unistd.h: Updated for Linux mit-pthreads/net/Makefile.inc: Updated for Linux mit-pthreads/pthreads/fd.c: Updated for Linux mit-pthreads/pthreads/fd_kern.c: Updated for Linux mit-pthreads/pthreads/fd_sysv.c: Updated for Linux mit-pthreads/pthreads/signal.c: Updated for Linux mit-pthreads/pthreads/wrapper.c: Updated for Linux mit-pthreads/stdlib/getopt.c: Updated for Linux sql/share/charsets/cp1251.conf: Updates for 3.23.14 sql/share/charsets/croat.conf: Updates for 3.23.14 sql/share/charsets/danish.conf: Updates for 3.23.14 sql/share/charsets/dec8.conf: Updates for 3.23.14 sql/share/charsets/dos.conf: Updates for 3.23.14 sql/share/charsets/german1.conf: Updates for 3.23.14 sql/share/charsets/greek.conf: Updates for 3.23.14 sql/share/charsets/hebrew.conf: Updates for 3.23.14 sql/share/charsets/hp8.conf: Updates for 3.23.14 sql/share/charsets/hungarian.conf: Updates for 3.23.14 sql/share/charsets/koi8_ru.conf: Updates for 3.23.14 sql/share/charsets/koi8_ukr.conf: Updates for 3.23.14 sql/share/charsets/latin1.conf: Updates for 3.23.14 sql/share/charsets/latin2.conf: Updates for 3.23.14 sql/share/charsets/swe7.conf: Updates for 3.23.14 sql/share/charsets/usa7.conf: Updates for 3.23.14 sql/share/charsets/win1251.conf: Updates for 3.23.14 sql/share/charsets/win1251ukr.conf: Updates for 3.23.14 sql/Attic/mybinlogdump.cc: Fix for binary log include/Attic/m_ctype.h.in: Update for dynamic character sets strings/Attic/ct_init.c: Update for dynamic character sets strings/Attic/ctype-cp1251.c: Update for dynamic character sets strings/Attic/ctype-cp1257.c: Update for dynamic character sets strings/Attic/ctype-croat.c: Update for dynamic character sets strings/Attic/ctype-danish.c: Update for dynamic character sets strings/Attic/ctype-dec8.c: Update for dynamic character sets strings/Attic/ctype-dos.c: Update for dynamic character sets strings/Attic/ctype-estonia.c: Update for dynamic character sets strings/Attic/ctype-german1.c: Update for dynamic character sets strings/Attic/ctype-greek.c: Update for dynamic character sets strings/Attic/ctype-hebrew.c: Update for dynamic character sets strings/Attic/ctype-hp8.c: Update for dynamic character sets strings/Attic/ctype-hungarian.c: Update for dynamic character sets strings/Attic/ctype-koi8_ru.c: Update for dynamic character sets strings/Attic/ctype-koi8_ukr.c: Update for dynamic character sets strings/Attic/ctype-latin1.c: Update for dynamic character sets strings/Attic/ctype-latin2.c: Update for dynamic character sets strings/Attic/ctype-swe7.c: Update for dynamic character sets strings/Attic/ctype-usa7.c: Update for dynamic character sets strings/Attic/ctype-win1250.c: Update for dynamic character sets strings/Attic/ctype-win1251.c: Update for dynamic character sets strings/Attic/ctype-win1251ukr.c: Update for dynamic character sets mysys/.cvsignore: Update for dynamic character set handling client/Attic/libmysql.c: Update of new character sets. sql/share/charsets/Index: Update to 3.23.14 sql/share/charsets/README: Update to 3.23.14 sql/share/charsets/cp1257.conf: Update to 3.23.14 sql/share/charsets/estonia.conf: Update to 3.23.14 sql/share/charsets/win1250.conf: Update to 3.23.14 strings/.cvsignore: Update to 3.23.14 strings/Attic/bootstrap-ctype.c: Update to 3.23.14 strings/Attic/ctype.c.in: Update to 3.23.14 strings/ctype-ujis.c: Update to 3.23.14 BUILD/.cvsignore: Portability changes libmysql/.cvsignore: Portability changes mit-pthreads/GNUmakefile: Modifications to get MySQL 3.23.14 to build mit-pthreads/config.flags: ***MISSING WEAVE*** mit-pthreads/include/pthread/ac-types.h: Modifications to get MySQL 3.23.14 to build mit-pthreads/include/pthread/paths.h: Modifications to get MySQL 3.23.14 to build regex/main.c: Portability fixes sql/Attic/mini_client_errors.c: fixed up dependencies and symlinking in mini_client Build-tools/cvs-sanity-check: added a script to do a build from fresh CVS for sanity checking - make Tim, Tonu, and everybody else who has had problems with the stuff out of CVS not compiling happy include/t_ctype.h: Small updates by monty include/.cvsignore: Update to 3.23.15 include/mysql_version.h.in: Update to 3.23.15 isam/ChangeLog: Update to 3.23.15 sql-bench/limits/interbase.cfg: character sets patches + fix of order by sql-bench/Results-linux/ATIS-interbase-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results-linux/RUN-interbase-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results-linux/alter-table-interbase-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results-linux/big-tables-interbase-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results-linux/create-interbase-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results-linux/insert-interbase-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results-linux/select-interbase-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results-linux/wisconsin-interbase-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** Docs/net_doc.txt: Fixes for Win32 sql/share/Makefile.am: Update at work to get MySQL to configure include/Attic/mysql_com.h.in: Update of benchmarks and other small stuff sql-bench/Results-linux/ATIS-interbase-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/ATIS-mysql-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/RUN-interbase-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/RUN-mysql-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/alter-table-interbase-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/alter-table-mysql-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/big-tables-interbase-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/big-tables-mysql-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/connect-interbase-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/connect-interbase-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results-linux/connect-mysql-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/create-interbase-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/create-mysql-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/insert-interbase-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/insert-mysql-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/select-interbase-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/select-mysql-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/wisconsin-interbase-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/Results-linux/wisconsin-mysql-Linux_2.2.14_5.0_i686-cmp-interbase,mysql: ***MISSING WEAVE*** sql-bench/limits/mimer.cfg: Update of benchmarks and other small stuff sql/Attic/mini_client.c: Update to get Berkeley db to work. sql/Attic/net_serv.c: Update to get Berkeley db to work. sql/Attic/lex_hash.h: lex_hash.h is a pain in the neck for cvs diff scripts/mysql_convert_table_format.sh: Update for 3.23.16 include/getopt.h: Update for 3.23.16 Docs/Support/.cvsignore: Update for build scripts/mysqlhotcopy.sh: Update for 3.23.16 Docs/Attic/myisam.doc: Mirror addition, Broken Image fix, renamed myisam.doc -> myisam.txt (because it's really text. :). Docs/myisam.txt: Mirror addition, Broken Image fix, renamed myisam.doc -> myisam.txt (because it's really text. :). sql-bench/ChangeLog: Updates for 3.23.17 tests/big_record.pl: Updates for 3.23.17 tests/export.pl: Updates for 3.23.17 tests/fork2_test.pl: Updates for 3.23.17 tests/fork3_test.pl: Updates for 3.23.17 tests/fork_test.pl: Updates for 3.23.17 tests/grant.pl: Updates for 3.23.17 tests/insert_and_repair.pl: Updates for 3.23.17 tests/lock_test.pl: Updates for 3.23.17 tests/pmail.pl: Updates for 3.23.17 sql/.cvsignore: Update for 3.23.17 sql-bench/Results/Attic/ATIS-mysql-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/ATIS-mysql-Linux_2.2.1_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/ATIS-mysql_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/ATIS-pg-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/ATIS-pg_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/RUN-mysql-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/RUN-mysql-Linux_2.2.1_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/RUN-mysql_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/RUN-pg-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/RUN-pg_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/alter-table-mysql-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/alter-table-mysql-Linux_2.2.1_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/alter-table-mysql_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/alter-table-pg-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/alter-table-pg_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/big-tables-mysql-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/big-tables-mysql-Linux_2.2.1_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/big-tables-mysql_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/big-tables-pg-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/big-tables-pg_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/connect-mysql-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/connect-mysql-Linux_2.2.1_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/connect-mysql_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/connect-pg-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/connect-pg_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/create-mysql-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/create-mysql-Linux_2.2.1_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/create-mysql_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/create-pg-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/create-pg_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/insert-mysql-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/insert-mysql-Linux_2.2.1_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/insert-mysql_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/insert-pg-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/insert-pg_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/select-mysql-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/select-mysql-Linux_2.2.1_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/select-mysql_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/select-pg-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/select-pg_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/wisconsin-mysql-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/wisconsin-mysql-Linux_2.2.1_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/wisconsin-mysql_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/wisconsin-pg-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/Attic/wisconsin-pg_fast-Linux_2.2.10_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/ATIS-pg-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/RUN-pg-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/alter-table-pg-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/big-tables-pg-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/connect-pg-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/create-pg-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/insert-pg-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/select-pg-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/wisconsin-pg-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** support-files/Attic/my-example.cnf.sh: Updates to 3.23.17 support-files/Attic/my-huge.cfg.sh: Update for 3.23.17 support-files/Attic/my-large.cfg.sh: Update for 3.23.17 support-files/Attic/my-medium.cfg.sh: Update for 3.23.17 support-files/Attic/my-small.cfg.sh: Update for 3.23.17 sql-bench/limits/pg.cfg: Updates to 3.23.17 support-files/my-small.cnf.sh: Updates to 3.23.17 dbug/dbug.c: update 3.23.17 for Monty mysys/getopt1.c: update 3.23.17 for Monty readline/complete.c: update 3.23.17 for Monty regex/regcomp.c: update 3.23.17 for Monty regex/regex2.h: update 3.23.17 for Monty regex/regexec.c: update 3.23.17 for Monty regex/regexp.c: update 3.23.17 for Monty sql-bench/Results/ATIS-mysql-win98: update 3.23.17 for Monty sql-bench/Results/RUN-mysql-win98: update 3.23.17 for Monty sql-bench/Results/alter-table-mysql-win98: update 3.23.17 for Monty sql-bench/Results/big-tables-mysql-win98: update 3.23.17 for Monty sql-bench/Results/connect-mysql-win98: update 3.23.17 for Monty sql-bench/Results/create-mysql-win98: update 3.23.17 for Monty sql-bench/Results/insert-mysql-win98: update 3.23.17 for Monty sql-bench/Results/select-mysql-win98: update 3.23.17 for Monty sql-bench/Results/wisconsin-mysql-win98: update 3.23.17 for Monty sql-bench/Results-linux/ATIS-mysql_fast-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/alter-table-mysql_fast-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/big-tables-mysql_fast-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/create-mysql_fast-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/insert-mysql_fast-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/wisconsin-mysql_fast-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** tests/test_delayed_insert.pl: update 3.23.17 for Monty vio/Vio.h: update 3.23.17 for Monty vio/VioPipe.h: update 3.23.17 for Monty vio/violite.h: update 3.23.17 for Monty sql-bench/limits/access.cfg: Update for 3.23.17 sql-bench/limits/ms-sql.cfg: Update for 3.23.17 sql-bench/limits/oracle.cfg: Update for 3.23.17 BUILD/compile-alpha-ccc: Update to 3.23.18 BUILD/compile-alpha-debug: Update to 3.23.18 BUILD/compile-alpha: Update to 3.23.18 BUILD/compile-pentium-gcov: Update to 3.23.18 BUILD/compile-pentium-myodbc: Update to 3.23.18 BUILD/compile-pentium: Update to 3.23.18 BUILD/compile-solaris-sparc-purify: Update to 3.23.18 BUILD/compile-solaris-sparc: Update to 3.23.18 client/Attic/net.c: Update to 3.23.18 sql-bench/Results/ATIS-mysql-Linux_2.2.14_i686_xeon: Update to 3.23.18 sql-bench/Results/RUN-mysql-Linux_2.2.14_i686_xeon: Update to 3.23.18 sql-bench/Results/alter-table-mysql-Linux_2.2.14_i686_xeon: Update to 3.23.18 sql-bench/Results/big-tables-mysql-Linux_2.2.14_i686_xeon: Update to 3.23.18 sql-bench/Results/connect-mysql-Linux_2.2.14_i686_xeon: Update to 3.23.18 sql-bench/Results/create-mysql-Linux_2.2.14_i686_xeon: Update to 3.23.18 sql-bench/Results/insert-mysql-Linux_2.2.14_i686_xeon: Update to 3.23.18 sql-bench/Results/select-mysql-Linux_2.2.14_i686_xeon: Update to 3.23.18 sql-bench/Results/wisconsin-mysql-Linux_2.2.14_i686_xeon: Update to 3.23.18 sql-bench/Results-linux/RUN-mysql_fast-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/connect-mysql_fast-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/select-mysql_fast-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** mysql-test/mybin/mysql-test_install_db: Initial checkin of mysql-test subdir. mysql-test/mysql-test-run: Quick commit before I checkout a new tree. Docs/Tutorial-MySQL-final.txt: Update for 3.23.19-beta Build-tools/Do-rpm: Fix of wrong CVS update sql-bench/Results/ATIS-mysql-NT_4.0: Fix of wrong CVS update sql-bench/Results/RUN-mysql-NT_4.0: Fix of wrong CVS update sql-bench/Results/alter-table-mysql-NT_4.0: Fix of wrong CVS update sql-bench/Results/big-tables-mysql-NT_4.0: Fix of wrong CVS update sql-bench/Results/connect-mysql-NT_4.0: Fix of wrong CVS update sql-bench/Results/create-mysql-NT_4.0: Fix of wrong CVS update sql-bench/Results/insert-mysql-NT_4.0: Fix of wrong CVS update sql-bench/Results/select-mysql-NT_4.0: Fix of wrong CVS update sql-bench/Results/wisconsin-mysql-NT_4.0: Fix of wrong CVS update acconfig.h: Change of copyright to GPL/LGPL client/.cvsignore: Change of copyright to GPL/LGPL client/completion_hash.h: Change of copyright to GPL/LGPL client/connect_test.c: Change of copyright to GPL/LGPL client/errmsg.c: Change of copyright to GPL/LGPL client/insert_test.c: Change of copyright to GPL/LGPL client/list_test.c: Change of copyright to GPL/LGPL client/my_readline.h: Change of copyright to GPL/LGPL client/password.c: Change of copyright to GPL/LGPL client/readline.cc: Change of copyright to GPL/LGPL client/select_test.c: Change of copyright to GPL/LGPL client/showdb_test.c: Change of copyright to GPL/LGPL client/sql_string.cc: Change of copyright to GPL/LGPL client/sql_string.h: Change of copyright to GPL/LGPL client/ssl_test.c: Change of copyright to GPL/LGPL client/thread_test.c: Change of copyright to GPL/LGPL client/violite.c: Change of copyright to GPL/LGPL dbug/Makefile.am: Change of copyright to GPL/LGPL extra/comp_err.c: Change of copyright to GPL/LGPL extra/perror.c: Change of copyright to GPL/LGPL extra/replace.c: Change of copyright to GPL/LGPL extra/resolveip.c: Change of copyright to GPL/LGPL heap/Makefile.am: Change of copyright to GPL/LGPL heap/_check.c: Change of copyright to GPL/LGPL heap/_rectest.c: Change of copyright to GPL/LGPL heap/heapdef.h: Change of copyright to GPL/LGPL heap/hp_block.c: Change of copyright to GPL/LGPL heap/hp_clear.c: Change of copyright to GPL/LGPL heap/hp_close.c: Change of copyright to GPL/LGPL heap/hp_create.c: Change of copyright to GPL/LGPL heap/hp_delete.c: Change of copyright to GPL/LGPL heap/hp_extra.c: Change of copyright to GPL/LGPL heap/hp_hash.c: Change of copyright to GPL/LGPL heap/hp_info.c: Change of copyright to GPL/LGPL heap/hp_open.c: Change of copyright to GPL/LGPL heap/hp_panic.c: Change of copyright to GPL/LGPL heap/hp_rename.c: Change of copyright to GPL/LGPL heap/hp_rfirst.c: Change of copyright to GPL/LGPL heap/hp_rlast.c: Change of copyright to GPL/LGPL heap/hp_rnext.c: Change of copyright to GPL/LGPL heap/hp_rprev.c: Change of copyright to GPL/LGPL heap/hp_rrnd.c: Change of copyright to GPL/LGPL heap/hp_rsame.c: Change of copyright to GPL/LGPL heap/hp_scan.c: Change of copyright to GPL/LGPL heap/hp_static.c: Change of copyright to GPL/LGPL heap/hp_test1.c: Change of copyright to GPL/LGPL heap/hp_test2.c: Change of copyright to GPL/LGPL heap/hp_update.c: Change of copyright to GPL/LGPL heap/hp_write.c: Change of copyright to GPL/LGPL include/dbug.h: Change of copyright to GPL/LGPL include/hash.h: Change of copyright to GPL/LGPL include/heap.h: Change of copyright to GPL/LGPL include/m_ctype.h: Change of copyright to GPL/LGPL include/m_string.h: Change of copyright to GPL/LGPL include/merge.h: Change of copyright to GPL/LGPL include/my_alarm.h: Change of copyright to GPL/LGPL include/my_dir.h: Change of copyright to GPL/LGPL include/my_list.h: Change of copyright to GPL/LGPL include/my_net.h: Change of copyright to GPL/LGPL include/my_no_pthread.h: Change of copyright to GPL/LGPL include/my_nosys.h: Change of copyright to GPL/LGPL include/my_pthread.h: Change of copyright to GPL/LGPL include/my_sys.h: Change of copyright to GPL/LGPL include/my_tree.h: Change of copyright to GPL/LGPL include/myisammrg.h: Change of copyright to GPL/LGPL include/myisampack.h: Change of copyright to GPL/LGPL include/mysys_err.h: Change of copyright to GPL/LGPL include/nisam.h: Change of copyright to GPL/LGPL include/queues.h: Change of copyright to GPL/LGPL include/raid.h: Change of copyright to GPL/LGPL include/sslopt-case.h: Change of copyright to GPL/LGPL include/sslopt-longopts.h: Change of copyright to GPL/LGPL include/sslopt-usage.h: Change of copyright to GPL/LGPL include/sslopt-vars.h: Change of copyright to GPL/LGPL include/thr_alarm.h: Change of copyright to GPL/LGPL include/thr_lock.h: Change of copyright to GPL/LGPL include/violite.h: Change of copyright to GPL/LGPL isam/Makefile.am: Change of copyright to GPL/LGPL isam/_cache.c: Change of copyright to GPL/LGPL isam/_dynrec.c: Change of copyright to GPL/LGPL isam/_key.c: Change of copyright to GPL/LGPL isam/_locking.c: Change of copyright to GPL/LGPL isam/_packrec.c: Change of copyright to GPL/LGPL isam/_page.c: Change of copyright to GPL/LGPL isam/_search.c: Change of copyright to GPL/LGPL isam/_statrec.c: Change of copyright to GPL/LGPL isam/changed.c: Change of copyright to GPL/LGPL isam/close.c: Change of copyright to GPL/LGPL isam/create.c: Change of copyright to GPL/LGPL isam/delete.c: Change of copyright to GPL/LGPL isam/extra.c: Change of copyright to GPL/LGPL isam/isamchk.c: Change of copyright to GPL/LGPL isam/isamlog.c: Change of copyright to GPL/LGPL isam/log.c: Change of copyright to GPL/LGPL isam/open.c: Change of copyright to GPL/LGPL isam/pack_isam.c: Change of copyright to GPL/LGPL isam/panic.c: Change of copyright to GPL/LGPL isam/range.c: Change of copyright to GPL/LGPL isam/rfirst.c: Change of copyright to GPL/LGPL isam/rkey.c: Change of copyright to GPL/LGPL isam/rlast.c: Change of copyright to GPL/LGPL isam/rnext.c: Change of copyright to GPL/LGPL isam/rprev.c: Change of copyright to GPL/LGPL isam/rrnd.c: Change of copyright to GPL/LGPL isam/rsame.c: Change of copyright to GPL/LGPL isam/rsamepos.c: Change of copyright to GPL/LGPL isam/sort.c: Change of copyright to GPL/LGPL isam/static.c: Change of copyright to GPL/LGPL isam/test1.c: Change of copyright to GPL/LGPL isam/test3.c: Change of copyright to GPL/LGPL libmysql/Makefile.am: Change of copyright to GPL/LGPL libmysql/conf_to_src.c: Change of copyright to GPL/LGPL libmysql/dll.c: Change of copyright to GPL/LGPL libmysql/get_password.c: Change of copyright to GPL/LGPL libmysql/password.c: Change of copyright to GPL/LGPL libmysql/violite.c: Change of copyright to GPL/LGPL man/Makefile.am: Change of copyright to GPL/LGPL merge/Makefile.am: Change of copyright to GPL/LGPL merge/_locking.c: Change of copyright to GPL/LGPL merge/close.c: Change of copyright to GPL/LGPL merge/create.c: Change of copyright to GPL/LGPL merge/delete.c: Change of copyright to GPL/LGPL merge/extra.c: Change of copyright to GPL/LGPL merge/info.c: Change of copyright to GPL/LGPL merge/mrgdef.h: Change of copyright to GPL/LGPL merge/open.c: Change of copyright to GPL/LGPL merge/panic.c: Change of copyright to GPL/LGPL merge/rrnd.c: Change of copyright to GPL/LGPL merge/rsame.c: Change of copyright to GPL/LGPL merge/static.c: Change of copyright to GPL/LGPL merge/update.c: Change of copyright to GPL/LGPL myisam/ft_eval.c: Change of copyright to GPL/LGPL myisam/ft_eval.h: Change of copyright to GPL/LGPL myisam/ft_parser.c: Change of copyright to GPL/LGPL myisam/ft_static.c: Change of copyright to GPL/LGPL myisam/ft_stem.c: Change of copyright to GPL/LGPL myisam/ft_stopwords.c: Change of copyright to GPL/LGPL myisam/ft_test1.c: Change of copyright to GPL/LGPL myisam/ft_test1.h: Change of copyright to GPL/LGPL myisam/ftdefs.h: Change of copyright to GPL/LGPL myisam/fulltext.h: Change of copyright to GPL/LGPL myisam/mi_cache.c: Change of copyright to GPL/LGPL myisam/mi_changed.c: Change of copyright to GPL/LGPL myisam/mi_checksum.c: Change of copyright to GPL/LGPL myisam/mi_dbug.c: Change of copyright to GPL/LGPL myisam/mi_delete_all.c: Change of copyright to GPL/LGPL myisam/mi_delete_table.c: Change of copyright to GPL/LGPL myisam/mi_dynrec.c: Change of copyright to GPL/LGPL myisam/mi_info.c: Change of copyright to GPL/LGPL myisam/mi_key.c: Change of copyright to GPL/LGPL myisam/mi_packrec.c: Change of copyright to GPL/LGPL myisam/mi_page.c: Change of copyright to GPL/LGPL myisam/mi_range.c: Change of copyright to GPL/LGPL myisam/mi_rename.c: Change of copyright to GPL/LGPL myisam/mi_rfirst.c: Change of copyright to GPL/LGPL myisam/mi_rkey.c: Change of copyright to GPL/LGPL myisam/mi_rlast.c: Change of copyright to GPL/LGPL myisam/mi_rnext.c: Change of copyright to GPL/LGPL myisam/mi_rprev.c: Change of copyright to GPL/LGPL myisam/mi_rrnd.c: Change of copyright to GPL/LGPL myisam/mi_rsame.c: Change of copyright to GPL/LGPL myisam/mi_rsamepos.c: Change of copyright to GPL/LGPL myisam/mi_scan.c: Change of copyright to GPL/LGPL myisam/mi_static.c: Change of copyright to GPL/LGPL myisam/mi_statrec.c: Change of copyright to GPL/LGPL myisam/mi_test1.c: Change of copyright to GPL/LGPL myisam/mi_test2.c: Change of copyright to GPL/LGPL myisam/mi_test3.c: Change of copyright to GPL/LGPL myisam/mi_unique.c: Change of copyright to GPL/LGPL myisam/myisamlog.c: Change of copyright to GPL/LGPL myisam/sort.c: Change of copyright to GPL/LGPL myisammrg/Makefile.am: Change of copyright to GPL/LGPL myisammrg/mymrgdef.h: Change of copyright to GPL/LGPL myisammrg/myrg_close.c: Change of copyright to GPL/LGPL myisammrg/myrg_create.c: Change of copyright to GPL/LGPL myisammrg/myrg_delete.c: Change of copyright to GPL/LGPL myisammrg/myrg_extra.c: Change of copyright to GPL/LGPL myisammrg/myrg_info.c: Change of copyright to GPL/LGPL myisammrg/myrg_locking.c: Change of copyright to GPL/LGPL myisammrg/myrg_open.c: Change of copyright to GPL/LGPL myisammrg/myrg_panic.c: Change of copyright to GPL/LGPL myisammrg/myrg_rrnd.c: Change of copyright to GPL/LGPL myisammrg/myrg_rsame.c: Change of copyright to GPL/LGPL myisammrg/myrg_static.c: Change of copyright to GPL/LGPL myisammrg/myrg_update.c: Change of copyright to GPL/LGPL mysys/Makefile.am: Change of copyright to GPL/LGPL mysys/array.c: Change of copyright to GPL/LGPL mysys/charset.c: Change of copyright to GPL/LGPL mysys/checksum.c: Change of copyright to GPL/LGPL mysys/default.c: Change of copyright to GPL/LGPL mysys/errors.c: Change of copyright to GPL/LGPL mysys/getvar.c: Change of copyright to GPL/LGPL mysys/hash.c: Change of copyright to GPL/LGPL mysys/list.c: Change of copyright to GPL/LGPL mysys/make-conf.c: Change of copyright to GPL/LGPL mysys/mf_brkhant.c: Change of copyright to GPL/LGPL mysys/mf_cache.c: Change of copyright to GPL/LGPL mysys/mf_casecnv.c: Change of copyright to GPL/LGPL mysys/mf_dirname.c: Change of copyright to GPL/LGPL mysys/mf_fn_ext.c: Change of copyright to GPL/LGPL mysys/mf_format.c: Change of copyright to GPL/LGPL mysys/mf_getdate.c: Change of copyright to GPL/LGPL mysys/mf_iocache.c: Change of copyright to GPL/LGPL mysys/mf_keycache.c: Change of copyright to GPL/LGPL mysys/mf_loadpath.c: Change of copyright to GPL/LGPL mysys/mf_pack2.c: Change of copyright to GPL/LGPL mysys/mf_path.c: Change of copyright to GPL/LGPL mysys/mf_qsort.c: Change of copyright to GPL/LGPL mysys/mf_qsort2.c: Change of copyright to GPL/LGPL mysys/mf_radix.c: Change of copyright to GPL/LGPL mysys/mf_reccache.c: ***MISSING WEAVE*** mysys/mf_same.c: Change of copyright to GPL/LGPL mysys/mf_sleep.c: Change of copyright to GPL/LGPL mysys/mf_sort.c: Change of copyright to GPL/LGPL mysys/mf_soundex.c: Change of copyright to GPL/LGPL mysys/mf_stripp.c: Change of copyright to GPL/LGPL mysys/mf_unixpath.c: Change of copyright to GPL/LGPL mysys/mf_util.c: Change of copyright to GPL/LGPL mysys/mf_wcomp.c: Change of copyright to GPL/LGPL mysys/mf_wfile.c: Change of copyright to GPL/LGPL mysys/mulalloc.c: Change of copyright to GPL/LGPL mysys/my_alarm.c: Change of copyright to GPL/LGPL mysys/my_alloc.c: Change of copyright to GPL/LGPL mysys/my_append.c: Change of copyright to GPL/LGPL mysys/my_chsize.c: Change of copyright to GPL/LGPL mysys/my_clock.c: Change of copyright to GPL/LGPL mysys/my_compress.c: Change of copyright to GPL/LGPL mysys/my_copy.c: Change of copyright to GPL/LGPL mysys/my_create.c: Change of copyright to GPL/LGPL mysys/my_delete.c: Change of copyright to GPL/LGPL mysys/my_div.c: Change of copyright to GPL/LGPL mysys/my_error.c: Change of copyright to GPL/LGPL mysys/my_fopen.c: Change of copyright to GPL/LGPL mysys/my_fstream.c: Change of copyright to GPL/LGPL mysys/my_getwd.c: Change of copyright to GPL/LGPL mysys/my_init.c: Change of copyright to GPL/LGPL mysys/my_lib.c: Change of copyright to GPL/LGPL mysys/my_lock.c: Change of copyright to GPL/LGPL mysys/my_lockmem.c: Change of copyright to GPL/LGPL mysys/my_lread.c: Change of copyright to GPL/LGPL mysys/my_lwrite.c: Change of copyright to GPL/LGPL mysys/my_malloc.c: Change of copyright to GPL/LGPL mysys/my_messnc.c: Change of copyright to GPL/LGPL mysys/my_mkdir.c: Change of copyright to GPL/LGPL mysys/my_net.c: Change of copyright to GPL/LGPL mysys/my_once.c: Change of copyright to GPL/LGPL mysys/my_open.c: Change of copyright to GPL/LGPL mysys/my_pread.c: Change of copyright to GPL/LGPL mysys/my_pthread.c: Change of copyright to GPL/LGPL mysys/my_quick.c: Change of copyright to GPL/LGPL mysys/my_read.c: Change of copyright to GPL/LGPL mysys/my_realloc.c: Change of copyright to GPL/LGPL mysys/my_redel.c: Change of copyright to GPL/LGPL mysys/my_rename.c: Change of copyright to GPL/LGPL mysys/my_seek.c: Change of copyright to GPL/LGPL mysys/my_static.c: Change of copyright to GPL/LGPL mysys/my_static.h: Change of copyright to GPL/LGPL mysys/my_tempnam.c: Change of copyright to GPL/LGPL mysys/my_vsnprintf.c: Change of copyright to GPL/LGPL mysys/my_wincond.c: Change of copyright to GPL/LGPL mysys/my_winthread.c: Change of copyright to GPL/LGPL mysys/my_write.c: Change of copyright to GPL/LGPL mysys/mysys_priv.h: Change of copyright to GPL/LGPL mysys/ptr_cmp.c: Change of copyright to GPL/LGPL mysys/queues.c: Change of copyright to GPL/LGPL mysys/raid.cc: Change of copyright to GPL/LGPL mysys/safemalloc.c: Change of copyright to GPL/LGPL mysys/string.c: Change of copyright to GPL/LGPL mysys/test_charset.c: Change of copyright to GPL/LGPL mysys/test_dir.c: Change of copyright to GPL/LGPL mysys/test_fn.c: Change of copyright to GPL/LGPL mysys/test_vsnprintf.c: Change of copyright to GPL/LGPL mysys/testhash.c: Change of copyright to GPL/LGPL mysys/thr_alarm.c: Change of copyright to GPL/LGPL mysys/thr_lock.c: Change of copyright to GPL/LGPL mysys/thr_mutex.c: Change of copyright to GPL/LGPL mysys/thr_rwlock.c: Change of copyright to GPL/LGPL mysys/tree.c: Change of copyright to GPL/LGPL mysys/typelib.c: Change of copyright to GPL/LGPL regex/Makefile.am: Change of copyright to GPL/LGPL sql/cache_manager.cc: Change of copyright to GPL/LGPL sql/cache_manager.h: Change of copyright to GPL/LGPL sql/convert.cc: Change of copyright to GPL/LGPL sql/custom_conf.h: Change of copyright to GPL/LGPL sql/derror.cc: Change of copyright to GPL/LGPL sql/field_conv.cc: Change of copyright to GPL/LGPL sql/frm_crypt.cc: Change of copyright to GPL/LGPL sql/ha_heap.cc: Change of copyright to GPL/LGPL sql/ha_heap.h: Change of copyright to GPL/LGPL sql/ha_isam.cc: Change of copyright to GPL/LGPL sql/ha_isammrg.cc: Change of copyright to GPL/LGPL sql/hash_filo.cc: Change of copyright to GPL/LGPL sql/hash_filo.h: Change of copyright to GPL/LGPL sql/hostname.cc: Change of copyright to GPL/LGPL sql/init.cc: Change of copyright to GPL/LGPL sql/item_buff.cc: Change of copyright to GPL/LGPL sql/item_cmpfunc.h: Change of copyright to GPL/LGPL sql/item_create.cc: Change of copyright to GPL/LGPL sql/item_create.h: Change of copyright to GPL/LGPL sql/item_strfunc.cc: Change of copyright to GPL/LGPL sql/item_strfunc.h: Change of copyright to GPL/LGPL sql/item_sum.cc: Change of copyright to GPL/LGPL sql/item_sum.h: Change of copyright to GPL/LGPL sql/item_uniq.cc: Change of copyright to GPL/LGPL sql/item_uniq.h: Change of copyright to GPL/LGPL sql/key.cc: Change of copyright to GPL/LGPL sql/lex_symbol.h: Change of copyright to GPL/LGPL sql/lock.cc: Change of copyright to GPL/LGPL sql/matherr.c: Change of copyright to GPL/LGPL sql/mf_iocache.cc: Change of copyright to GPL/LGPL sql/mini_client.h: Change of copyright to GPL/LGPL sql/my_lock.c: Change of copyright to GPL/LGPL sql/opt_sum.cc: Change of copyright to GPL/LGPL sql/password.c: Change of copyright to GPL/LGPL sql/procedure.cc: Change of copyright to GPL/LGPL sql/procedure.h: Change of copyright to GPL/LGPL sql/sql_acl.h: Change of copyright to GPL/LGPL sql/sql_analyse.cc: Change of copyright to GPL/LGPL sql/sql_cache.cc: Change of copyright to GPL/LGPL sql/sql_crypt.cc: Change of copyright to GPL/LGPL sql/sql_crypt.h: Change of copyright to GPL/LGPL sql/sql_list.cc: Change of copyright to GPL/LGPL sql/sql_list.h: Change of copyright to GPL/LGPL sql/sql_map.cc: Change of copyright to GPL/LGPL sql/sql_map.h: Change of copyright to GPL/LGPL sql/sql_string.h: Change of copyright to GPL/LGPL sql/sql_test.cc: Change of copyright to GPL/LGPL sql/sql_udf.cc: Change of copyright to GPL/LGPL sql/sql_udf.h: Change of copyright to GPL/LGPL sql/thr_malloc.cc: Change of copyright to GPL/LGPL sql/udf_example.cc: Change of copyright to GPL/LGPL sql/unireg.cc: Change of copyright to GPL/LGPL sql/unireg.h: Change of copyright to GPL/LGPL sql/violite.c: Change of copyright to GPL/LGPL sql-bench/Makefile.am: Change of copyright to GPL/LGPL sql-bench/bench-init.pl.sh: Change of copyright to GPL/LGPL sql-bench/copy-db.sh: Change of copyright to GPL/LGPL sql-bench/run-all-tests.sh: Change of copyright to GPL/LGPL sql-bench/server-cfg.sh: Change of copyright to GPL/LGPL sql-bench/test-ATIS.sh: Change of copyright to GPL/LGPL sql-bench/test-alter-table.sh: Change of copyright to GPL/LGPL sql-bench/test-big-tables.sh: Change of copyright to GPL/LGPL sql-bench/test-connect.sh: Change of copyright to GPL/LGPL sql-bench/test-create.sh: Change of copyright to GPL/LGPL sql-bench/test-insert.sh: Change of copyright to GPL/LGPL sql-bench/test-select.sh: Change of copyright to GPL/LGPL sql-bench/test-wisconsin.sh: Change of copyright to GPL/LGPL sql-bench/Results/ATIS-mysql-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/ATIS-mysql_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/ATIS-pg_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/ATIS-pg_fast-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results/RUN-mysql-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/RUN-mysql_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/RUN-pg_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/RUN-pg_fast-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results/alter-table-mysql-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/alter-table-mysql_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/alter-table-pg_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/alter-table-pg_fast-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results/big-tables-mysql-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/big-tables-mysql_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/big-tables-pg_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/big-tables-pg_fast-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results/connect-mysql-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/connect-mysql_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/connect-pg_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/connect-pg_fast-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results/create-mysql-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/create-mysql_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/create-pg_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/create-pg_fast-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results/insert-mysql-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/insert-mysql_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/insert-pg_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/select-mysql-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/select-mysql_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/select-pg_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/wisconsin-mysql-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/wisconsin-mysql_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** sql-bench/Results/wisconsin-pg_fast-Linux_2.2.14_5.0_i686-cmp-mysql,pg: ***MISSING WEAVE*** strings/Makefile.am: Change of copyright to GPL/LGPL strings/README: Change of copyright to GPL/LGPL strings/atof.c: Change of copyright to GPL/LGPL strings/bchange.c: Change of copyright to GPL/LGPL strings/bcmp.c: Change of copyright to GPL/LGPL strings/bcopy-duff.c: Change of copyright to GPL/LGPL strings/bmove512.c: Change of copyright to GPL/LGPL strings/bmove_upp-sparc.s: Change of copyright to GPL/LGPL strings/bmove_upp.c: Change of copyright to GPL/LGPL strings/conf_to_src.c: Change of copyright to GPL/LGPL strings/ctype-big5.c: Change of copyright to GPL/LGPL strings/ctype-euc_kr.c: Change of copyright to GPL/LGPL strings/ctype-gb2312.c: Change of copyright to GPL/LGPL strings/ctype-sjis.c: Change of copyright to GPL/LGPL strings/ctype.c: Change of copyright to GPL/LGPL strings/do_ctype.c: Change of copyright to GPL/LGPL strings/int2str.c: Change of copyright to GPL/LGPL strings/is_prefix.c: Change of copyright to GPL/LGPL strings/llstr.c: Change of copyright to GPL/LGPL strings/longlong2str-x86.s: Change of copyright to GPL/LGPL strings/longlong2str.c: Change of copyright to GPL/LGPL strings/macros.asm: Change of copyright to GPL/LGPL strings/memcmp.c: Change of copyright to GPL/LGPL strings/memcpy.c: Change of copyright to GPL/LGPL strings/ptr_cmp.asm: Change of copyright to GPL/LGPL strings/str2int.c: Change of copyright to GPL/LGPL strings/str_test.c: Change of copyright to GPL/LGPL strings/strappend-sparc.s: Change of copyright to GPL/LGPL strings/strappend.c: Change of copyright to GPL/LGPL strings/strcend.c: Change of copyright to GPL/LGPL strings/strcont.c: Change of copyright to GPL/LGPL strings/strend-sparc.s: Change of copyright to GPL/LGPL strings/strfill.c: Change of copyright to GPL/LGPL strings/strings-x86.s: Change of copyright to GPL/LGPL strings/strings.asm: Change of copyright to GPL/LGPL strings/strinstr-sparc.s: Change of copyright to GPL/LGPL strings/strinstr.c: Change of copyright to GPL/LGPL strings/strmake-sparc.s: Change of copyright to GPL/LGPL strings/strmake.c: Change of copyright to GPL/LGPL strings/strmov-sparc.s: Change of copyright to GPL/LGPL strings/strmov.c: Change of copyright to GPL/LGPL strings/strnmov-sparc.s: Change of copyright to GPL/LGPL strings/strnmov.c: Change of copyright to GPL/LGPL strings/strstr-sparc.s: Change of copyright to GPL/LGPL strings/strto.c: Change of copyright to GPL/LGPL strings/strtol.c: Change of copyright to GPL/LGPL strings/strtoll.c: Change of copyright to GPL/LGPL strings/strtoul.c: Change of copyright to GPL/LGPL strings/strtoull.c: Change of copyright to GPL/LGPL strings/strxmov-sparc.s: Change of copyright to GPL/LGPL strings/strxmov.asm: Change of copyright to GPL/LGPL strings/udiv.c: Change of copyright to GPL/LGPL support-files/Makefile.am: Change of copyright to GPL/LGPL tests/Makefile.am: Change of copyright to GPL/LGPL vio/Makefile.am: Change of copyright to GPL/LGPL isam/.cvsignore: Updates for 3.23.19 myisam/.cvsignore: Updates for 3.23.19 sql-bench/Results/insert-pg_fast-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results/select-pg_fast-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql-bench/Results/wisconsin-pg_fast-Linux_2.2.14_5.0_i686: ***MISSING WEAVE*** sql/sql_analyse.h: Fix bug when memory wasn't freed sql/mysqlbinlog.cc: Small fixes sql/share/romanian/errmsg.txt: ***MISSING WEAVE*** include/mysql_com.h: Replication update/LOAD TABLE FROM MASTER + other fixes client/mysql-test.c: ***MISSING WEAVE*** myisam/Attic/ft_global.h: This file is now in include/ extra/Attic/print_defaults.c: Updates for text search + ORDER BY extra/Makefile.am: Updates for text search + ORDER BY extra/my_print_defaults.c: Updates for text search + ORDER BY include/mysqld_error.h: Updates for text search + ORDER BY sql/item_cmpfunc.cc: Updates for text search + ORDER BY sql/opt_range.h: Updates for text search + ORDER BY sql/sql_lex.cc: Updates for text search + ORDER BY sql-bench/crash-me.sh: Updates for text search + ORDER BY sql-bench/limits/mysql.cfg: Updates for text search + ORDER BY sql/share/czech/errmsg.sys: Updates for text search + ORDER BY sql/share/czech/errmsg.txt: Updates for text search + ORDER BY sql/share/danish/errmsg.sys: Updates for text search + ORDER BY sql/share/danish/errmsg.txt: Updates for text search + ORDER BY sql/share/dutch/errmsg.sys: Updates for text search + ORDER BY sql/share/dutch/errmsg.txt: Updates for text search + ORDER BY sql/share/english/errmsg.sys: Updates for text search + ORDER BY sql/share/english/errmsg.txt: Updates for text search + ORDER BY sql/share/estonia/errmsg.sys: Updates for text search + ORDER BY sql/share/estonia/errmsg.txt: Updates for text search + ORDER BY sql/share/french/errmsg.sys: Updates for text search + ORDER BY sql/share/french/errmsg.txt: Updates for text search + ORDER BY sql/share/german/errmsg.sys: Updates for text search + ORDER BY sql/share/german/errmsg.txt: Updates for text search + ORDER BY sql/share/greek/errmsg.sys: Updates for text search + ORDER BY sql/share/greek/errmsg.txt: Updates for text search + ORDER BY sql/share/hungarian/errmsg.sys: Updates for text search + ORDER BY sql/share/hungarian/errmsg.txt: Updates for text search + ORDER BY sql/share/japanese/errmsg.sys: Updates for text search + ORDER BY sql/share/japanese/errmsg.txt: Updates for text search + ORDER BY sql/share/korean/errmsg.sys: Updates for text search + ORDER BY sql/share/korean/errmsg.txt: Updates for text search + ORDER BY sql/share/norwegian/errmsg.txt: Updates for text search + ORDER BY sql/share/norwegian-ny/errmsg.txt: Updates for text search + ORDER BY sql/share/polish/errmsg.sys: Updates for text search + ORDER BY sql/share/polish/errmsg.txt: Updates for text search + ORDER BY sql/share/portuguese/errmsg.sys: Updates for text search + ORDER BY sql/share/portuguese/errmsg.txt: Updates for text search + ORDER BY sql/share/romania/errmsg.sys: Updates for text search + ORDER BY sql/share/romania/errmsg.txt: Updates for text search + ORDER BY sql/share/russian/errmsg.sys: Updates for text search + ORDER BY sql/share/russian/errmsg.txt: Updates for text search + ORDER BY sql/share/slovak/errmsg.sys: Updates for text search + ORDER BY sql/share/slovak/errmsg.txt: Updates for text search + ORDER BY sql/share/spanish/errmsg.sys: Updates for text search + ORDER BY sql/share/spanish/errmsg.txt: Updates for text search + ORDER BY sql/share/swedish/errmsg.OLD: Updates for text search + ORDER BY sql/share/swedish/errmsg.sys: Updates for text search + ORDER BY sql/share/swedish/errmsg.txt: Updates for text search + ORDER BY support-files/mysql.server-sys5.sh: Updates for text search + ORDER BY extra/.cvsignore: Fix for update + BDB tables isam/_dbug.c: Fix for update + BDB tables myisam/mi_delete.c: Fix for update + BDB tables myisam/mi_rnext_same.c: Fix for update + BDB tables myisam/mi_search.c: Fix for update + BDB tables sql/table.cc: Fix of core dump bugs myisam/Makefile.am: Aded missing file sql/ha_berkeley.h: Fix DELETE FROM table_name problem Build-tools/Do-all-build-steps: Update to final 3.23.20 Build-tools/mysql-copyright-2: Update to final 3.23.20 Build-tools/mysql-copyright: Update to final 3.23.20 Docs/.cvsignore: Update to final 3.23.20 scripts/make_binary_distribution.sh: Update to final 3.23.20 Docs/internals.texi: Fix of licenses issues. sql/ha_isam.h: Added patch by Sergei for MATCH + some bug fixes. sql/ha_isammrg.h: Added patch by Sergei for MATCH + some bug fixes. sql/ha_myisammrg.h: Added patch by Sergei for MATCH + some bug fixes. myisam/ft_search.c: Fix of portability bug include/ft_global.h: Fix of portability bug sql/log_event.cc: One more safety fix sql/log_event.h: One more safety fix isam/test2.c: Update to 3.23.21 isam/update.c: Update to 3.23.21 myisam/ChangeLog: Update to 3.23.21 myisam/mi_test_all.sh: Update to 3.23.21 myisam/mi_update.c: Update to 3.23.21 myisam/mi_write.c: Update to 3.23.21 scripts/.cvsignore: Update to 3.23.21 scripts/mysql_config.sh: Update to 3.23.21 sql/filesort.cc: Update to 3.23.21 Docs/Support/texi2html: removed NOSAVE attrib from TABLE tags, non-standard HTML. include/Attic/config-win32.h: Made update log ASCII 0 safe myisam/mi_test_all: ***MISSING WEAVE*** sql/sql_acl.cc: Made update log ASCII 0 safe sql/sql_db.cc: Made update log ASCII 0 safe sql/sql_delete.cc: Made update log ASCII 0 safe sql/sql_insert.cc: Made update log ASCII 0 safe sql/sql_load.cc: Made update log ASCII 0 safe sql/sql_select.h: Made update log ASCII 0 safe sql/sql_update.cc: Made update log ASCII 0 safe sql/table.h: Made update log ASCII 0 safe strings/ctype-czech.c: Made update log ASCII 0 safe support-files/maxsql.spec.sh: Made update log ASCII 0 safe client/mysqlimport.c: Update to 3.23.21 client/mysqlshow.c: Update to 3.23.21 include/mysql.h: Added mysql_character_set_name() mit-pthreads/net/gethostname.c: Added mysql_character_set_name() scripts/Makefile.am: Added mysql_character_set_name() client/Makefile.am: portability fixes scripts/mysql_install_db.sh: portability fixes support-files/mysql.spec.sh: Added mysql_config config.h.in: ***MISSING WEAVE*** client/mysqldump.c: Small fixes heap/hp_rkey.c: Small fixes sql-bench/compare-results.sh: Small fixes tests/mail_to_db.pl: Small fixes acinclude.m4: Configure updates for 3.23.22 BUILD/compile-pentium-debug: Configure updates for 3.23.22 Docs/Makefile.am: Configure updates for 3.23.22 client/get_password.c: Configure updates for 3.23.22 client/mysqladmin.c: Configure updates for 3.23.22 include/Makefile.am: Configure updates for 3.23.22 include/my_global.h: ***MISSING WEAVE*** isam/info.c: Configure updates for 3.23.22 isam/isamdef.h: Configure updates for 3.23.22 isam/write.c: Configure updates for 3.23.22 sql/records.cc: Configure updates for 3.23.22 sql-bench/print-limit-table: Configure updates for 3.23.22 sql-bench/limits/mysql-3.23.cfg: Configure updates for 3.23.22 support-files/my-huge.cnf.sh: Configure updates for 3.23.22 support-files/my-large.cnf.sh: Configure updates for 3.23.22 support-files/my-medium.cnf.sh: Configure updates for 3.23.22 myisam/ft_update.c: This is to make ft-code to ignore keyseg.length at all and to index the whole VARCHAR/BLOB instead... Makefile.am: Fixed gen_lex_hash recursion myisam/myisampack.c: Fixes for 3.23.22 sql/ChangeLog: Fixes for 3.23.22 sql/nt_servc.cc: Fixes for 3.23.22 sql/sql_class.cc: Fixes for 3.23.22 include/my_base.h: Fix for BDB and MERGE tables sql/ha_myisammrg.cc: Fix for BDB and MERGE tables Docs/LICENSE: Update for 3.23.22 config.sub: Update for ia64 Build-tools/Do-compile-all: ***MISSING WEAVE*** scripts/safe_mysqld.sh: Small bug fixes for 3.23.22 support-files/.cvsignore: Small bug fixes for 3.23.22 scripts/mysql_find_rows.sh: Critical bug fixes sql/sql_class.h: SHOW SLAVE STATUS, change in SHOW MASTER STATUS repl-tests/include/master-slave.inc: Replication test cases repl-tests/test-dump/run.test: Replication test cases repl-tests/test-dump/table-dump-check.master: Replication test cases repl-tests/test-dump/table-dump-select.master: Replication test cases repl-tests/test-repl-ts/repl-timestamp.master: Replication test cases repl-tests/test-repl-ts/run.test: Replication test cases repl-tests/test-repl/foo-dump-master.master: Replication test cases repl-tests/test-repl/foo-dump-slave.master: Replication test cases repl-tests/test-repl/run.test: Replication test cases repl-tests/test-repl/sum-wlen-master.master: Replication test cases repl-tests/test-repl/sum-wlen-slave.master: Replication test cases Images/.cvsignore: Update of div reported bugs include/config-win.h: Update of div reported bugs mysys/mf_pack.c: Update of div reported bugs sql/field.cc: Update of div reported bugs sql/field.h: Update of div reported bugs sql/ha_myisam.h: Update of div reported bugs sql/handler.h: Update of div reported bugs sql/item.cc: Update of div reported bugs sql/item_func.h: Update of div reported bugs sql/item_timefunc.cc: Update of div reported bugs sql/item_timefunc.h: Update of div reported bugs sql/sql_string.cc: Update of div reported bugs sql/sql_table.cc: Update of div reported bugs sql/structs.h: Update of div reported bugs sql/time.cc: Update of div reported bugs strings/ctype-gbk.c: Update of div reported bugs strings/ctype-tis620.c: Update of div reported bugs strings/r_strinstr.c: Update of div reported bugs strings/strnlen.c: Update of div reported bugs support-files/mysql.server.sh: Update of div reported bugs myisam/mi_locking.c: Small bug fixes myisam/myisamdef.h: Small bug fixes mysys/my_thr_init.c: Small bug fixes myisam/mi_close.c: Changed mutex THR_lock_isam -> THR_lock_myisam myisam/mi_create.c: Changed mutex THR_lock_isam -> THR_lock_myisam myisam/mi_extra.c: Changed mutex THR_lock_isam -> THR_lock_myisam myisam/mi_log.c: Changed mutex THR_lock_isam -> THR_lock_myisam myisam/mi_open.c: Changed mutex THR_lock_isam -> THR_lock_myisam myisam/mi_panic.c: Changed mutex THR_lock_isam -> THR_lock_myisam myisam/myisamchk.c: Changed mutex THR_lock_isam -> THR_lock_myisam sql/item_func.cc: Don't let MySQL use ft-keys in non-ft way sql/opt_range.cc: Don't let MySQL use ft-keys in non-ft way sql-bench/Results-linux/ATIS-mysql-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/RUN-mysql-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/alter-table-mysql-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/big-tables-mysql-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/connect-mysql-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/create-mysql-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/insert-mysql-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/select-mysql-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql-bench/Results-linux/wisconsin-mysql-Linux_2.2.13_SMP_alpha: ***MISSING WEAVE*** sql/share/italian/errmsg.sys: new translated error messages sql/share/italian/errmsg.txt: new translated error messages libmysql/errmsg.c: Fix to get 'Too big packet' error + fixes for Ia64 libmysql/libmysql.c: Fix to get 'Too big packet' error + fixes for Ia64 libmysql/net.c: Fix to get 'Too big packet' error + fixes for Ia64 include/errmsg.h: Fix to get 'Too big packet' mysql.proj: Update for 3.23.22 client/mysql.cc: Fix for rehash on reconnect (By Jeremey) readline/rlstdc.h: portability fixes sql/Makefile.am: Hack to force lex_hash.h to be generated sql/ha_berkeley.cc: Fixes for Berekely DB sql/handler.cc: Fixes for Berekely DB sql/item.h: Small fixes for 3.23.22 sql/net_serv.cc: Small fixes for 3.23.22 client/completion_hash.cc: Fixes for Ia64 sql/mini_client.cc: Fixes for Ia64 sql/sql_select.cc: Fixes for Ia64 .cvsignore: Update at work for release myisam/mi_check.c: Fix bug in ANALYZE TABLE sql/ha_myisam.cc: Fix bug in ANALYZE TABLE include/myisam.h: Fix bug in ANALYZE TABLE configure.in: Fix for AIX 4.3 Build-tools/Do-compile: Fix for local perl libraries sql/sql_show.cc: Fix for show processlist on SCO include/global.h: Fix for AIX 4.3 BUILD/compile-ia64-O0-sgicc: Last minute updates for 3.23.22 BUILD/compile-ia64-O0: Last minute updates for 3.23.22 BUILD/compile-ia64-O2-sgicc: Last minute updates for 3.23.22 BUILD/compile-ia64-O2: Last minute updates for 3.23.22 BUILD/compile-ia64-O6: Last minute updates for 3.23.22 Docs/manual.texi: Added paragraph in introduction pointing to SQL and MySQL books, for newbies. sql/gen_lex_hash.cc: CHANGE MASTER TO and other fixes sql/lex.h: CHANGE MASTER TO and other fixes sql/log.cc: CHANGE MASTER TO and other fixes sql/mysql_priv.h: CHANGE MASTER TO and other fixes sql/mysqld.cc: CHANGE MASTER TO and other fixes sql/net_pkg.cc: CHANGE MASTER TO and other fixes sql/slave.cc: CHANGE MASTER TO and other fixes sql/sql_base.cc: CHANGE MASTER TO and other fixes sql/sql_lex.h: CHANGE MASTER TO and other fixes sql/sql_parse.cc: CHANGE MASTER TO and other fixes sql/sql_yacc.yy: CHANGE MASTER TO and other fixes
Diffstat (limited to 'isam')
-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
44 files changed, 17777 insertions, 0 deletions
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 */