diff options
author | unknown <bk@work.mysql.com> | 2000-07-31 21:29:14 +0200 |
---|---|---|
committer | unknown <bk@work.mysql.com> | 2000-07-31 21:29:14 +0200 |
commit | 84626f52fb1ca40ebe0175dfda8cc1a2931651c7 (patch) | |
tree | d253a359142dfc1ed247d5d4365d86972ea31109 /isam | |
parent | 3be46690f46f27f3e671de9a615d24d1554b9991 (diff) | |
download | mariadb-git-84626f52fb1ca40ebe0175dfda8cc1a2931651c7.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/.cvsignore | 10 | ||||
-rw-r--r-- | isam/ChangeLog | 186 | ||||
-rw-r--r-- | isam/Makefile.am | 51 | ||||
-rw-r--r-- | isam/_cache.c | 92 | ||||
-rw-r--r-- | isam/_dbug.c | 132 | ||||
-rw-r--r-- | isam/_dynrec.c | 1245 | ||||
-rw-r--r-- | isam/_key.c | 239 | ||||
-rw-r--r-- | isam/_locking.c | 345 | ||||
-rw-r--r-- | isam/_packrec.c | 1184 | ||||
-rw-r--r-- | isam/_page.c | 137 | ||||
-rw-r--r-- | isam/_search.c | 889 | ||||
-rw-r--r-- | isam/_statrec.c | 265 | ||||
-rw-r--r-- | isam/changed.c | 35 | ||||
-rw-r--r-- | isam/close.c | 91 | ||||
-rw-r--r-- | isam/create.c | 326 | ||||
-rw-r--r-- | isam/delete.c | 615 | ||||
-rw-r--r-- | isam/extra.c | 258 | ||||
-rw-r--r-- | isam/info.c | 77 | ||||
-rw-r--r-- | isam/isamchk.c | 3448 | ||||
-rw-r--r-- | isam/isamdef.h | 416 | ||||
-rw-r--r-- | isam/isamlog.c | 839 | ||||
-rw-r--r-- | isam/log.c | 156 | ||||
-rwxr-xr-x | isam/make-ccc | 3 | ||||
-rw-r--r-- | isam/open.c | 455 | ||||
-rw-r--r-- | isam/pack_isam.c | 2051 | ||||
-rw-r--r-- | isam/panic.c | 135 | ||||
-rw-r--r-- | isam/range.c | 191 | ||||
-rw-r--r-- | isam/rfirst.c | 34 | ||||
-rw-r--r-- | isam/rkey.c | 63 | ||||
-rw-r--r-- | isam/rlast.c | 34 | ||||
-rw-r--r-- | isam/rnext.c | 66 | ||||
-rw-r--r-- | isam/rprev.c | 63 | ||||
-rw-r--r-- | isam/rrnd.c | 55 | ||||
-rw-r--r-- | isam/rsame.c | 70 | ||||
-rw-r--r-- | isam/rsamepos.c | 59 | ||||
-rw-r--r-- | isam/sort.c | 558 | ||||
-rw-r--r-- | isam/static.c | 45 | ||||
-rw-r--r-- | isam/test1.c | 183 | ||||
-rw-r--r-- | isam/test2.c | 852 | ||||
-rw-r--r-- | isam/test3.c | 479 | ||||
-rwxr-xr-x | isam/test_all | 30 | ||||
-rw-r--r-- | isam/test_all.res | 356 | ||||
-rw-r--r-- | isam/update.c | 119 | ||||
-rw-r--r-- | isam/write.c | 840 |
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 */ |