1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Added all changes from old 4.0 version:

PSTACK, libmysqld and MySQL filesystem
UPDATE ... ORDER BY
DELETE ... ORDER BY
New faster fulltext handling
Faster compressed keys



Makefile.am:
  Added support for pstack and libmysqld_dir
acconfig.h:
  MySQL filesystem and PSTACK
acinclude.m4:
  MySQL File system
client/mysql.cc:
  Support for --xml
configure.in:
  Pstack, MySQL FS and libmysqld_dir
include/ft_global.h:
  Faster fulltext
include/my_pthread.h:
  Made c++ safe
include/myisam.h:
  Update for faster fulltext
include/mysql_com.h:
  new my_net_read()
include/violite.h:
  libmysqld
libmysql/net.c:
  New protocol that supports big packets
myisam/Makefile.am:
  Faster fulltext
myisam/ft_parser.c:
  Faster fulltext
myisam/ft_search.c:
  Faster fulltext
myisam/ft_update.c:
  Faster fulltext
myisam/ftdefs.h:
  Faster fulltext
myisam/mi_check.c:
  Faster fulltext
myisam/mi_open.c:
  Faster compressed keys
myisam/mi_search.c:
  Faster compressed keys
myisam/mi_update.c:
  Faster compressed keys
myisam/myisamdef.h:
  Faster compressed keys
myisam/sort.c:
  Faster compressed keys
mysql-test/mysql-test-run.sh:
  --skip-innobase and --skip-bdb
sql/ChangeLog:
  Changelog
sql/Makefile.am:
  PSTACK
sql/mysql_priv.h:
  New ORDER BY options and libmysqld
sql/mysqld.cc:
  PSTACK
sql/net_serv.cc:
  New protocol that supports big packets
sql/share/estonian/errmsg.txt:
  New error messages
sql/sql_base.cc:
  Better list_open_tabels
sql/sql_delete.cc:
  ORDER BY for delete
sql/sql_lex.cc:
  Added language convertation of all strings
sql/sql_parse.cc:
  Changes for libmysqld
  Use new ORDER BY options
sql/sql_show.cc:
  Character set convertations
  Use new list_open_tables function.
sql/sql_update.cc:
  UPDATE ... ORDER BY
sql/sql_yacc.yy:
  Clean up symbol definitions
  DELETE .. ORDER BY
  UPDATE .. ORDER BY
sql/table.h:
  new OPEN_TABLE_LIST structure
BitKeeper/etc/logging_ok:
  Logging to logging@openlogging.org accepted
This commit is contained in:
unknown
2001-04-11 13:04:03 +02:00
parent 0c97164177
commit 8dd2e5b8d9
87 changed files with 66688 additions and 1408 deletions

View File

@ -0,0 +1,13 @@
#! /bin/sh
path=`dirname $0`
. "$path/SETUP.sh"
extra_flags="$pentium_cflags $debug_cflags"
c_warnings="$c_warnings $debug_extra_warnings"
cxx_warnings="$cxx_warnings $debug_extra_warnings"
extra_configs="$pentium_configs $debug_configs"
extra_configs="$extra_configs --with-debug=full --with-mysqlfs --without-server --without-pstack"
. "$path/FINISH.sh"

View File

@ -1 +1 @@
heikki@donna.mysql.fi
monty@work.mysql.com

View File

@ -22,15 +22,18 @@ TAR = gtar
EXTRA_DIST = INSTALL-SOURCE README \
COPYING COPYING.LIB MIRRORS
SUBDIRS = include @docs_dirs@ @readline_dir@ \
@thread_dirs@ @sql_client_dirs@ \
@sql_server_dirs@ scripts tests man \
@bench_dirs@ support-files
@thread_dirs@ @pstack_dirs@ @sql_client_dirs@ \
@sql_server_dirs@ @libmysqld_dirs@ scripts tests man \
@bench_dirs@ support-files @fs_dirs@
# Relink after clean
CLEANFILES = linked_client_sources linked_server_sources linked_libmysql_sources linked_libmysql_r_sources linked_include_sources
linked_sources = linked_client_sources linked_server_sources \
linked_libmysql_sources linked_libmysql_r_sources \
linked_libmysqld_sources linked_include_sources
CLEANFILES = $(linked_sources)
# This is just so that the linking is done early.
config.h: linked_include_sources linked_client_sources linked_server_sources linked_libmysql_sources linked_libmysql_r_sources
config.h: $(linked_sources)
linked_include_sources:
cd include; $(MAKE) link_sources
@ -47,6 +50,10 @@ linked_libmysql_r_sources: linked_libmysql_sources
cd libmysql_r; $(MAKE) link_sources
echo timestamp > linked_libmysql_r_sources
linked_libmysqld_sources:
cd libmysqld; $(MAKE) link_sources
echo timestamp > linked_libmysqld_sources
#avoid recursive make calls in sql directory
linked_server_sources:
cd sql; rm -f mini_client_errors.c;@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c

View File

@ -111,6 +111,9 @@
/* sigwait with one argument */
#undef HAVE_NONPOSIX_SIGWAIT
/* ORBIT */
#undef HAVE_ORBIT
/* pthread_attr_setscope */
#undef HAVE_PTHREAD_ATTR_SETSCOPE
@ -230,6 +233,9 @@
#undef USE_MB
#undef USE_MB_IDENT
/* the pstack backtrace library */
#undef USE_PSTACK
/* Use MySQL RAID */
#undef USE_RAID

View File

@ -605,6 +605,53 @@ fi
AC_MSG_RESULT($ac_cv_conv_longlong_to_float)
])
AC_DEFUN(MYSQL_CHECK_MYSQLFS, [
AC_ARG_WITH([mysqlfs],
[\
--with-mysqlfs Include the corba-based MySQL file system],
[mysqlfs="$withval"],
[mysqlfs=no])
dnl Call MYSQL_CHECK_ORBIT even if mysqlfs == no, so that @orbit_*@
dnl get substituted.
MYSQL_CHECK_ORBIT
if test "$mysqlfs" = "yes"
then
if test -n "$orbit_exec_prefix"
then
fs_dirs=fs
else
AC_MSG_ERROR([mysqlfs requires ORBit, the CORBA ORB])
fi
else
fs_dirs=
fi
AC_SUBST([fs_dirs])
])
AC_DEFUN(MYSQL_CHECK_ORBIT, [
AC_MSG_CHECKING(for ORBit)
if test `which orbit-config`
then
orbit_exec_prefix=`orbit-config --exec-prefix`
orbit_includes=`orbit-config --cflags server`
orbit_libs=`orbit-config --libs server`
orbit_idl="$orbit_exec_prefix/bin/orbit-idl"
AC_MSG_RESULT(found!)
AC_DEFINE(HAVE_ORBIT)
else
orbit_exec_prefix=
orbit_includes=
orbit_libs=
orbit_idl=
AC_MSG_RESULT(not found)
fi
AC_SUBST(orbit_includes)
AC_SUBST(orbit_libs)
AC_SUBST(orbit_idl)
])
dnl ---------------------------------------------------------------------------
dnl Macro: MYSQL_CHECK_BDB
dnl Sets HAVE_BERKELEY_DB if inst library is found

View File

@ -19,9 +19,11 @@
*
* Written by:
* Michael 'Monty' Widenius
* Andi Gutmans <andi@zend.com>
* Andi Gutmans <andi@zend.com>
* Zeev Suraski <zeev@zend.com>
* Jani Tolonen <jani@mysql.com>
* Matt Wagner <mwagner@mysql.com>
* Jeremy Cole <jcole@mysql.com>
*
**/
@ -39,7 +41,7 @@
#include "my_readline.h"
#include <signal.h>
const char *VER="11.13";
const char *VER="11.14";
/* Don't try to make a nice table if the data is too big */
#define MAX_COLUMN_LENGTH 1024
@ -120,7 +122,7 @@ static bool info_flag=0,ignore_errors=0,wait_flag=0,quick=0,
no_rehash=0,skip_updates=0,safe_updates=0,one_database=0,
opt_compress=0,
vertical=0,skip_line_numbers=0,skip_column_names=0,opt_html=0,
opt_nopager=1, opt_outfile=0, no_named_cmds=1;
opt_xml=0,opt_nopager=1, opt_outfile=0, no_named_cmds=1;
static uint verbose=0,opt_silent=0,opt_mysql_port=0;
static my_string opt_mysql_unix_port=0;
static int connect_flag=CLIENT_INTERACTIVE;
@ -131,6 +133,11 @@ static String glob_buffer,old_buffer;
static int wait_time = 5;
static STATUS status;
static ulong select_limit,max_join_size,opt_connect_timeout=0;
static char *xmlmeta[] = {
"&", "&amp;",
"<", "&lt;",
0, 0
};
static char default_pager[FN_REFLEN];
char pager[FN_REFLEN], outfile[FN_REFLEN];
FILE *PAGER, *OUTFILE;
@ -166,6 +173,9 @@ static int sql_connect(char *host,char *database,char *user,char *password,
uint silent);
static int put_info(const char *str,INFO_TYPE info,uint error=0);
static void safe_put_field(const char *pos,ulong length);
static char *array_value(char **array, char *key);
static char *xmlencode(char *dest, char *src);
static void my_chomp(char *end);
static void init_pager();
static void end_pager();
static void init_tee();
@ -250,6 +260,7 @@ static bool add_line(String &buffer,char *line,char *in_string);
static void remove_cntrl(String &buffer);
static void print_table_data(MYSQL_RES *result);
static void print_table_data_html(MYSQL_RES *result);
static void print_table_data_xml(MYSQL_RES *result);
static void print_tab_data(MYSQL_RES *result);
static void print_table_data_vertically(MYSQL_RES *result);
static ulong start_timer(void);
@ -313,7 +324,7 @@ int main(int argc,char *argv[])
#ifdef HAVE_READLINE
initialize_readline(my_progname);
if (!status.batch && !quick && !opt_html)
if (!status.batch && !quick && !opt_html && !opt_xml)
{
/*read-history from file, default ~/.mysql_history*/
if (getenv("MYSQL_HISTFILE"))
@ -351,7 +362,7 @@ sig_handler mysql_end(int sig)
if (connected)
mysql_close(&mysql);
#ifdef HAVE_READLINE
if (!status.batch && !quick && ! opt_html)
if (!status.batch && !quick && !opt_html && !opt_xml)
{
/* write-history */
if (verbose)
@ -396,6 +407,7 @@ static struct option long_options[] =
{"force", no_argument, 0, 'f'},
{"help", no_argument, 0, '?'},
{"html", no_argument, 0, 'H'},
{"xml", no_argument, 0, 'X'},
{"host", required_argument, 0, 'h'},
{"ignore-spaces", no_argument, 0, 'i'},
{"no-auto-rehash",no_argument, 0, 'A'},
@ -490,6 +502,7 @@ static void usage(int version)
-i, --ignore-space Ignore space after function names.\n\
-h, --host=... Connect to host.\n\
-H, --html Produce HTML output.\n\
-X, --xml Produce XML output.\n\
-L, --skip-line-numbers\n\
Don't write line number for errors.\n");
#ifndef __WIN__
@ -564,7 +577,7 @@ static int get_options(int argc, char **argv)
set_all_changeable_vars(changeable_vars);
while ((c=getopt_long(argc,argv,
"?ABCD:LfgGHinNoqrstTU::vVw::WEe:h:O:P:S:u:#::p::",
"?ABCD:LfgGHXinNoqrstTU::vVw::WEe:h:O:P:S:u:#::p::",
long_options, &option_index)) != EOF)
{
switch(c) {
@ -676,6 +689,7 @@ static int get_options(int argc, char **argv)
case 'G': no_named_cmds=0; break;
case 'g': no_named_cmds=1; break;
case 'H': opt_html=1; break;
case 'X': opt_xml=1; break;
case 'i': connect_flag|= CLIENT_IGNORE_SPACE; break;
case 'B':
if (!status.batch)
@ -1433,6 +1447,8 @@ com_go(String *buffer,char *line __attribute__((unused)))
init_pager();
if (opt_html)
print_table_data_html(result);
else if (opt_xml)
print_table_data_xml(result);
else if (vertical)
print_table_data_vertically(result);
else if (opt_silent && verbose <= 2 && !output_tables)
@ -1635,6 +1651,49 @@ print_table_data_html(MYSQL_RES *result)
}
static void
print_table_data_xml(MYSQL_RES *result)
{
MYSQL_ROW cur;
MYSQL_FIELD *fields;
mysql_field_seek(result,0);
char *statement;
statement=(char*) my_malloc(strlen(glob_buffer.ptr())*5+1, MYF(MY_WME));
xmlencode(statement, (char*) glob_buffer.ptr());
(void) my_chomp(strend(statement));
tee_fprintf(PAGER,"<?xml version=\"1.0\"?>\n\n<resultset statement=\"%s\">", statement);
my_free(statement,MYF(MY_ALLOW_ZERO_PTR));
fields = mysql_fetch_fields(result);
while ((cur = mysql_fetch_row(result)))
{
(void) tee_fputs("\n <row>\n", PAGER);
for (uint i=0; i < mysql_num_fields(result); i++)
{
char *data;
ulong *lengths=mysql_fetch_lengths(result);
data=(char*) my_malloc(lengths[i]*5+1, MYF(MY_WME));
tee_fprintf(PAGER, "\t<%s>", (fields[i].name ?
(fields[i].name[0] ? fields[i].name :
" &nbsp; ") : "NULL"));
xmlencode(data, cur[i]);
safe_put_field(data, strlen(data));
tee_fprintf(PAGER, "</%s>\n", (fields[i].name ?
(fields[i].name[0] ? fields[i].name :
" &nbsp; ") : "NULL"));
my_free(data,MYF(MY_ALLOW_ZERO_PTR));
}
(void) tee_fputs(" </row>\n", PAGER);
}
(void) tee_fputs("</resultset>\n", PAGER);
}
static void
print_table_data_vertically(MYSQL_RES *result)
@ -1666,6 +1725,43 @@ print_table_data_vertically(MYSQL_RES *result)
}
}
static char
*array_value(char **array, char *key) {
int x;
for(x=0; array[x]; x+=2)
if(!strcmp(array[x], key))
return array[x+1];
return 0;
}
static char
*xmlencode(char *dest, char *src) {
char *p = src;
char *t;
char s[2] = { 0, 0 };
*dest = 0;
do {
s[0] = *p;
if(!(t=array_value(xmlmeta, s))) t = s;
strcat(dest, t);
} while(*p++);
return dest;
}
static void
my_chomp(char *end) {
char *mend;
mend = end;
do {
if (isspace(*mend)) {
*mend = '\0';
} else
mend--;
} while (mend && *mend);
}
static void
safe_put_field(const char *pos,ulong length)
@ -1696,7 +1792,7 @@ safe_put_field(const char *pos,ulong length)
tee_fputs("\\n", PAGER); // This too
else if (*pos == '\\')
tee_fputs("\\\\", PAGER);
else
else
tee_putc(*pos, PAGER);
}
}

View File

@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line!
AM_INIT_AUTOMAKE(mysql, 3.23.37)
AM_INIT_AUTOMAKE(mysql, 4.0.0)
AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10
@ -177,7 +177,7 @@ AC_DEFUN(AC_SYS_COMPILER_FLAG,
[
CFLAGS="[$]OLD_CFLAGS $1"
AC_TRY_RUN([int main(){exit(0);}],mysql_cv_option_$2=yes,mysql_cv_option_$2=no,mysql_cv_option_$2=no)
])
])
CFLAGS="[$]OLD_CFLAGS"
@ -654,6 +654,39 @@ int main()
if test -z "$atom_ops"; then atom_ops="no"; fi
AC_MSG_RESULT($atom_ops)
AC_ARG_WITH(pstack,
[ --without-pstack Don't use the pstack backtrace library],
[USE_PSTACK=$withval],
[USE_PSTACK=yes])
pstack_libs= pstack_dirs=
if test "$USE_PSTACK" = yes
then
have_libiberty= have_libbfd=
my_save_LIBS="$LIBS"
dnl I have no idea if this is a good test - can't find docs for libiberty
AC_CHECK_LIB([iberty], [fdmatch],
[have_libiberty=yes
AC_CHECK_LIB([bfd], [bfd_openr], [have_libbfd=yes], , [-liberty])])
LIBS="$my_save_LIBS"
AC_MSG_CHECKING([for pstack libs])
if test x"$have_libiberty" = xyes -a x"$have_libbfd" = xyes
then
pstack_dirs='$(top_srcdir)'/pstack
pstack_libs="$pstack_dirs/libpstack.a -lbfd -liberty"
AC_SUBST([pstack_dirs])
AC_SUBST([pstack_libs])
AC_DEFINE([USE_PSTACK])
AC_MSG_RESULT([yes])
dnl This check isn't needed, but might be nice to give some feedback....
dnl AC_CHECK_HEADER(libiberty.h,
dnl have_libiberty_h=yes,
dnl have_libiberty_h=no)
else
AC_MSG_RESULT([no (missing libbfd)])
fi
fi
fi
# Check for gtty if termio.h doesn't exists
@ -1581,6 +1614,27 @@ AC_ARG_WITH(server,
[with_server=yes]
)
AC_ARG_WITH(embedded-server,
[ --with-embedded-server Build the embedded server (libmysqld).],
[with_embedded_server=$withval],
[with_embedded_server=no]
)
MYSQL_CHECK_MYSQLFS
libmysqld_dirs=
if test "$with_embedded_server" = "yes"
then
libmysqld_dirs=libmysqld
# We can't build embedded library without building the server, because
# we depend on libmysys, libmystrings, libmyisam, etc.
with_server=yes
fi
# XXX: We need to add @libmysqld_extra_libs@ (or whatever) so that
# mysql_config --libmysqld-libs will print out something like
# -L/path/to/lib/mysql -lmysqld -lmyisam -lmysys -lmystrings -ldbug ...
AC_SUBST([libmysqld_dirs])
# Shall we build the docs?
AC_ARG_WITH(docs,
[ --without-docs Skip building of the documentation.],
@ -2017,13 +2071,13 @@ AC_OUTPUT(Makefile extra/Makefile mysys/Makefile isam/Makefile \
strings/Makefile regex/Makefile heap/Makefile \
bdb/Makefile \
myisam/Makefile myisammrg/Makefile \
man/Makefile \
readline/Makefile libmysql_r/Makefile libmysql/Makefile client/Makefile \
sql/Makefile sql/share/Makefile \
man/Makefile readline/Makefile \
libmysql_r/Makefile libmysqld/Makefile libmysql/Makefile client/Makefile \
pstack/Makefile sql/Makefile sql/share/Makefile \
merge/Makefile dbug/Makefile scripts/Makefile \
include/Makefile sql-bench/Makefile \
tests/Makefile Docs/Makefile support-files/Makefile \
mysql-test/Makefile \
mysql-test/Makefile fs/Makefile \
include/mysql_version.h
, , [
test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h

38
fs/CorbaFS.idl Normal file
View File

@ -0,0 +1,38 @@
// -----------------------------------------------------------------------------
// CorbaDS Module - Implement Kernel functionality in korbit
// -----------------------------------------------------------------------------
//
// Main source of information:
// http://www.cse.unsw.edu.au/~neilb/oss/linux-commentary/vfs.html
//
module CorbaFS {
struct dirent
{
long inode; // inode number
string name; // file name (null-terminated)
};
typedef sequence<dirent> DirEntSeq;
typedef sequence<octet> Buffer;
interface Inode {
void getStatus(out unsigned short mode, out unsigned long uid, out unsigned long gid,
out unsigned long size, out unsigned long inodeNum, out unsigned short numLinks,
out long atime, out long mtime, out long ctime);
void readpage(out Buffer buffer, in long size, in long offset);
void release();
};
interface FileSystem {
Inode getInode(in string path);
// DirectoryInode getStatus implementation must have S_IFDIR in the S_IFMT
// field of the mode value.
DirEntSeq readdir(in string path);
// SymlinkInode getStatus implementation must have S_IFLNK in the S_IFMT
// field of the mode value.
string readlink(in string filename);
};
};

93
fs/Makefile.am Normal file
View File

@ -0,0 +1,93 @@
# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#called from the top level Makefile
CFLAGS = $(ORBIT_CFLAGS) -g
LFLAGS = $(ORBIT_LIBS)
orbit_idl = @orbit_idl@
orbit_includes = @orbit_includes@
orbit_libs = @orbit_libs@
DISTCLEANFILES = CorbaFS-common.* CorbaFS-stubs.* CorbaFS-skels.* CorbaFS.h
MYSQLDATAdir = $(localstatedir)
MYSQLSHAREdir = $(pkgdatadir)
MYSQLBASEdir= $(prefix)
INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include \
-I$(srcdir)/../regex \
-I$(srcdir) -I../include -I.. -I. \
-I$(srcdir) -I../include -I.. -I. \
$(orbit_includes)
WRAPLIBS= @WRAPLIBS@
libexec_PROGRAMS = mysqlcorbafsd
noinst_PROGRAMS =mysqlfs_test
LDADD = ../libmysql/libmysqlclient.la $(orbit_libs)
mysqlcorbafsd_LDADD = $(LDADD) $(CXXLDFLAGS)
noinst_HEADERS =
mysqlfs_test_SOURCES = mysqlcorbafs_test.c CorbaFS-common.c CorbaFS-stubs.c libmysqlfs.c
mysqlcorbafsd_SOURCES = mysqlcorbafs.c CorbaFS-skels.c database.c CorbaFS-common.c libmysqlfs.c
DEFS = -DMYSQL_SERVER \
-DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
-DDATADIR="\"$(MYSQLDATAdir)\"" \
-DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
@DEFS@
# Don't put lex_hash.h in BUILT_SOURCES as this will give infinite recursion
BUILT_SOURCES = CorbaFS-common.c CorbaFS-stubs.c CorbaFS-skels.c CorbaFS.h
EXTRA_DIST = $(BUILT_SOURCES)
#YFLAGS = -d
OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\
__math.h time.h __time.h unistd.h __unistd.h types.h \
xtypes.h ac-types.h posix.h string.h __string.h \
errno.h socket.h inet.h dirent.h netdb.h \
cleanup.h cond.h debug_out.h fd.h kernel.h mutex.h \
prio_queue.h pthread_attr.h pthread_once.h queue.h\
sleep.h specific.h version.h pwd.h timers.h uio.h \
cdefs.h machdep.h signal.h __signal.h util.h lex.h \
wait.h
link_sources:
rm -f mini_client_errors.c
@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c
# Don't update the files from bitkeeper
%::SCCS/s.%
idltargets : CorbaFS.idl
$(ORBIT_IDL) CorbaFS.idl
$(orbit_idl) CorbaFS.idl
# individual rules
CorbaFS-stubs.c : CorbaFS.idl
$(orbit_idl) CorbaFS.idl
CorbaFS-common.c : CorbaFS.idl
$(orbit_idl) CorbaFS.idl
CorbaFS-skels.c : CorbaFS.idl
$(orbit_idl) CorbaFS.idl
#CorbaFS-client.c : CorbaFS.h
#CorbaFS-server.c : CorbaFS.h
CorbaFS.h : CorbaFS.idl
$(orbit_idl) CorbaFS.idl

58
fs/README Normal file
View File

@ -0,0 +1,58 @@
MySQL Filesystem
T<EFBFBD>nu Samuel - tonu@mysql.com
Some additional information is available on http://no.spam.ee/~tonu/mysqlfs.html
WARNING: Experimental code and known to crash computer.
Instructions, how to get this stuff working:
1. Make sure you have ORBit, includeing development libraries installed. They should be version 0.5.3 or later.
- I am lazy man and use default ones included with my RedHat:
[root@localhost /root]# rpm -qa | grep ORBit
ORBit-0.5.3-2
ORBit-devel-0.5.3-2
[root@localhost /root]#
2. Prepare kernel to include korbit:
- Get Linux 2.4.1 kernel source. (very possibly this patch works on 2.4.0 without modifications too)
- unpack it
- apply patch named "korbit-kernel-2.4.1-patch" on it.
- make menuconfig
- In section "Networking options":
...
[*] Kernel ORB (EXPERIMENTAL)
...
<M> CORBA User-space FileSystem (EXPERIMENTAL)
...
- make dep ; make bzlilo ; make modules ; make modules_install
- reboot
- Execute: insmod /lib/modules/$(uname -r)/kernel/net/korbit/modules/CorbaFS/client/corba-corbafs-client.o
You should see "gethostname() = localhost". Look at known bug 3 in the end of this doc.
3. Make sure MySQL server is working on your system
- On my RedHat 7.0 I execute "/etc/init.d/mysqld start"
4. Prepare MySQL FS daemon
- Get MySQL 4.0 from repository OR get MySQL FS source from http://no.spam.ee/~tonu/mysqlfs.html
- unpack it. In MySQL 4.0 source this is located in directory named "fs". cd into it.
- make
- Execute command "./RunServer"
5. mount MySQL server to disk tree
- Execute command "mkdir /mnt/mysql"
- Execute command "mount -t corbafs -o `cat /tmp/mysqlcorbafs.ior` none /mnt/mysql/"
- Check you SQL server content by executing "ls -la /mnt/mysql/"
Known bugs:
1. User bugs. fix user ;)
2. MySQL FS daemon will crash or will be stopped when cobrafs is mounted, then there is no way
to unmount disks anymore. This is korbit business to handle such cases and I had no time to dig
into korbit code.
3. host name returned by gethostname() should be "localhost" or korbit will crash. Also "localhost"
must be first string after 127.0.0.1 in /etc/hosts

2
fs/RunServer.sh Executable file
View File

@ -0,0 +1,2 @@
.libs/mysqlcorbafsd -ORBIIOPUSock=0 -ORBIIOPIPv4=1 --debug='d:t:o,~/mysqlfsd.trace' $*
#.libs/mysqlcorbafsd -ORBIIOPUSock=0 -ORBIIOPIPv4=1 $*

629
fs/database.c Normal file
View File

@ -0,0 +1,629 @@
/* Copyright (C) 2000 db AB & db Finland AB & TCX DataKonsult AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Database functions
*
* Using these functions we emulate filesystem behaviour on top of SQL
* database.
* Written by T<>nu Samuel <tonu@please.do.not.remove.this.spam.ee>
*
* FIXME:
* - Direct handling of database handlers without SQL parsing overhead
* - connection pool
* - configurable function name/file name mappings
*/
#include "libmysqlfs.h"
#include "mysqlcorbafs.h"
#include <unistd.h>
#include <string.h>
#include <my_sys.h>
DYNAMIC_ARRAY field_array;
/*
* ** dbConnect -- connects to the host and selects DB.
* ** Also checks whether the tablename is a valid table name.
* */
int db_connect(char *host, char *user,char *passwd)
{
DBUG_ENTER("db_connect");
DBUG_PRINT("enter",("host: '%s', user: '%s', passwd: '%s'", host, user, passwd));
if (verbose)
{
fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost");
}
mysql_init(&connection);
if (opt_compress)
mysql_options(&connection,MYSQL_OPT_COMPRESS,NullS);
#ifdef HAVE_OPENSSL
if (opt_use_ssl)
mysql_ssl_set(&connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath);
#endif
if (!(sock= mysql_real_connect(&connection,host,user,passwd,
NULL,opt_mysql_port,opt_mysql_unix_port,0)))
{
DBerror(&connection, "when trying to connect");
DBUG_RETURN(1);
}
DBUG_RETURN(0);
} /* dbConnect */
/*
* ** dbDisconnect -- disconnects from the host.
* */
void db_disconnect(char *host)
{
DBUG_ENTER("db_disconnect");
DBUG_PRINT("enter",("host: '%s'", host));
if (verbose)
fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
mysql_close(sock);
DBUG_VOID_RETURN;
} /* dbDisconnect */
#define OUTPUT(x) strcpy(buffptr,x); buffptr+=strlen(x);
#define OUTPUT_TOP(x) strcpy(topptr,x); topptr+=strlen(x);
#define OUTPUT_MIDDLE(x) strcpy(midptr,x); midptr+=strlen(x);
#define OUTPUT_BOTTOM(x) strcpy(botptr,x); botptr+=strlen(x);
#define OUTPUT_HEADER(x) strcpy(hdrptr,x); hdrptr+=strlen(x);
void db_show_result(MYSQL* sock, char *b, struct format *f)
{
MYSQL_ROW row;
MYSQL_RES *result;
MYSQL_FIELD *field;
char *buffptr;
char topseparator[BUFLEN]="";
char middleseparator[BUFLEN]="";
char bottomseparator[BUFLEN]="";
char header[BUFLEN]="";
char *topptr=topseparator;
char *midptr=middleseparator;
char *botptr=bottomseparator;
char *hdrptr=header;
uint i,count, length;
DBUG_ENTER("db_show_result");
DBUG_PRINT("enter",("b: '%s', f '%x'", b, f));
result=mysql_store_result(sock);
buffptr=b;
OUTPUT(f->tablestart)
OUTPUT_TOP(f->leftuppercorner);
OUTPUT_MIDDLE(f->leftcross);
OUTPUT_BOTTOM(f->leftdowncorner);
OUTPUT_HEADER(f->headerrowstart);
count=mysql_num_fields(result);
// while ((field = mysql_fetch_field(result)))
for(i=0 ; i < count ; ++i)
{
field = mysql_fetch_field(result);
length=(uint) strlen(field->name);
OUTPUT_HEADER(f->headercellstart);
length=max(length,field->max_length);
if (length < 4 && !IS_NOT_NULL(field->flags))
length=4; // Room for "NULL"
field->max_length=length;
memset(topptr,'=',field->max_length);
memset(midptr,'-',field->max_length);
memset(botptr,'=',field->max_length);
sprintf(hdrptr,"%-*s",field->max_length,field->name);
//num_flag[off]= IS_NUM(field->type);
topptr+=field->max_length;
midptr+=field->max_length;
botptr+=field->max_length;
hdrptr+=field->max_length;
if(i<count-1) {
OUTPUT_TOP(f->topcross);
OUTPUT_MIDDLE(f->middlecross);
OUTPUT_BOTTOM(f->bottomcross);
OUTPUT_HEADER(f->headercellseparator);
}
}
OUTPUT_TOP(f->rightuppercorner);
OUTPUT_MIDDLE(f->rightcross);
OUTPUT_BOTTOM(f->rightdowncorner);
OUTPUT_HEADER(f->headercellend);
OUTPUT_HEADER(f->headerrowend);
OUTPUT(topseparator);
OUTPUT(header);
OUTPUT(middleseparator);
while(row=mysql_fetch_row(result)) {
mysql_field_seek(result,0);
OUTPUT(f->contentrowstart);
for(i=0 ; i < mysql_field_count(sock); ++i) {
field = mysql_fetch_field(result);
OUTPUT(f->contentcellstart);
sprintf(buffptr,"%-*s",field->max_length,row[i]);
buffptr+=field->max_length;
if(i==mysql_field_count(sock))
{
OUTPUT(f->contentcellend);
} else {
OUTPUT(f->contentcellseparator);
}
}
OUTPUT(f->contentrowend);
}
OUTPUT(bottomseparator);
OUTPUT(f->tableend);
mysql_free_result(result);
DBUG_VOID_RETURN;
}
int db_function(char *b,const char *server, const char *database,const char *table,const char *field, const char *value, const char* path, struct func_st *function)
{
char buff[BUFLEN];
int i;
DBUG_ENTER("db_function");
DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s', field: '%s', path: '%s'", b, database, table, field,path));
if(*database) {
if (mysql_select_db(sock,database))
{
printf("error when changing database to'%s'\n",database);
DBUG_RETURN(-1);
}
}
sprintf(buff,"%s",function->function);
search_and_replace("$database",database,buff);
search_and_replace("$table",table,buff);
search_and_replace("$field",field,buff);
search_and_replace("$value",value,buff);
DBUG_PRINT("info",("path: '%s'",path));
DBUG_PRINT("info",("sum: '%d'",(database[0] ? strlen(database)+1 : 0) +(table[0] ? strlen(table)+1 : 0) +(field[0] ? strlen(field)+1 : 0) +(value[0] ? strlen(value)+1 : 0) +1));
search_and_replace("$*",path+
(server[0] ? strlen(server)+1 : 0) +
(database[0] ? strlen(database)+1 : 0) +
(table[0] ? strlen(table)+1 : 0) +
(field[0] ? strlen(field)+1 : 0) +
(value[0] ? strlen(value)+1 : 0) +
function->length +
1,buff);
DBUG_PRINT("info",("Executing constructed function query: '%s'", buff));
if (mysql_query(sock, buff))
{
printf("error when executing '%s'\n",buff);
sprintf(b,"ERROR %d: %s",mysql_error(sock),mysql_error(sock));
DBUG_VOID_RETURN;
}
db_show_result(sock, b, &Human);
DBUG_PRINT("info",("Returning: %s", b));
DBUG_RETURN(1);
}
int db_show_field(char *b,const char *database,const char *table, const char *field,const char *value, const char *param)
{
MYSQL_RES *result;
MYSQL_ROW row;
char buff[BUFLEN];
int i=0;
my_string *ptr;
DBUG_ENTER("db_show_field");
DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s', field: '%s' value: '%s'", b, database, table, field, value));
/* We cant output fields when one of these variables is missing */
if (!(database[0] && table[0] && field[0]))
DBUG_RETURN(-1);
init_dynamic_array(&field_array, sizeof(buff), 4096, 1024);
if (mysql_select_db(sock,database))
{
printf("error when changing database to'%s'\n",database);
delete_dynamic(&field_array);
DBUG_RETURN(-1);
}
if(param) {
sprintf(buff,"%s",param);
} else {
sprintf(buff,"select %s from %s where %s='%s' LIMIT 1",field,table,field,value);
}
if (mysql_query(sock, buff))
{
printf("error when executing '%s'\n",buff);
delete_dynamic(&field_array);
DBUG_RETURN(-1);
}
db_show_result(sock,b,&Human);
/* if(result=mysql_use_result(sock)) {
while(row=mysql_fetch_row(result))
{
strcpy(&b[i][BUFLEN],row[0]);
DBUG_PRINT("info",("field %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
// ptr = (*dynamic_element(&field_array,i,row[0]));
i++;
}
}
// fix_filenames((char *)b);
mysql_free_result(result);
*/
delete_dynamic(&field_array);
DBUG_RETURN(i);
}
int db_show_fields(char *b,const char *database,const char *table)
{
MYSQL_RES *result;
MYSQL_ROW row;
MYSQL_FIELD *field;
char buff[BUFLEN];
int i=0;
DBUG_ENTER("show_fields");
DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s'", b, database, table));
if (mysql_select_db(sock,database))
{
printf("error when changing database to'%s'\n",database);
DBUG_RETURN(-1);
}
if(result=mysql_list_fields(sock,buff,NULL)) {
while(row=mysql_fetch_row(result))
{
strcpy(&b[i*BUFLEN],row[0]);
DBUG_PRINT("info",("field %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
i++;
}
}
mysql_free_result(result);
DBUG_RETURN(i);
}
int db_show_primary_keys(char *b,const char *database, const char *table)
{
MYSQL_RES *result;
MYSQL_ROW row;
char buff[BUFLEN];
char buff2[BUFLEN];
unsigned int i;
DBUG_ENTER("db_show_primary_keys");
DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s'", b, database, table));
if (mysql_select_db(sock,database))
{
printf("error when changing database to '%s'\n",database);
DBUG_RETURN(-1);
}
sprintf(buff,"show keys from %s",table);
if (mysql_query(sock, buff))
{
printf("error when executing '%s'\n",buff);
DBUG_RETURN(0);
}
buff2[0]='\0';
if(result=mysql_use_result(sock)) {
while(row=mysql_fetch_row(result)) {
if(!strcasecmp(row[2],"PRIMARY")) {
strcat(buff2,row[4]);
strcat(buff2,",\"_\",");
}
}
buff2[strlen(buff2)-5]='\0';
if(!buff2[0])
DBUG_RETURN(-1); // No PRIMARY keys in table
DBUG_PRINT("info",("Keys: %s<- \n", buff2));
} else
DBUG_RETURN(-1); // No keys in table
sprintf(buff,"SELECT CONCAT(%s) AS X FROM %s LIMIT 256",buff2,table);
if (mysql_query(sock, buff))
{
printf("error when executing '%s'\n",buff);
DBUG_RETURN(0);
}
i=0;
if(result=mysql_use_result(sock)) {
while(row=mysql_fetch_row(result))
{
strcpy(&b[i*BUFLEN],row[0]);
fix_filenames(&b[i*BUFLEN]);
DBUG_PRINT("info",("primarykey %s at %x, %i", &b[i*BUFLEN],&b[i*BUFLEN],i));
if(i++ >= MAXDIRS)
break;
}
}
mysql_free_result(result);
DBUG_RETURN(i);
}
int db_show_keys(char *b,const char *database, const char *table)
{
MYSQL_RES *result;
MYSQL_ROW row;
char buff[BUFLEN];
int i=0;
DBUG_ENTER("show_keys");
DBUG_PRINT("enter",("buffer: '%s', database: '%s', table: '%s'", b, database, table));
if (mysql_select_db(sock,database))
{
printf("error when changing database to'%s'\n",database);
DBUG_RETURN(-1);
}
sprintf(buff,"show keys from %s",table);
if (mysql_query(sock, buff))
{
printf("error when executing '%s'\n",buff);
DBUG_RETURN(0);
}
if(result=mysql_use_result(sock)) {
while(row=mysql_fetch_row(result))
{
strcpy(&b[i*BUFLEN],row[0]);
DBUG_PRINT("info",("Key %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
i++;
}
}
mysql_free_result(result);
DBUG_RETURN(i);
}
int db_show_tables(char *b,const char *database)
{
MYSQL_RES *result;
MYSQL_ROW row;
char buff[BUFLEN];
int i=0;
DBUG_ENTER("db_show_tables");
DBUG_PRINT("enter",("buffer: '%s', database: '%s'", b, database));
if (mysql_select_db(sock,database))
{
printf("error when changing database to '%s'\n",database);
DBUG_RETURN(-1);
}
if(result=mysql_list_tables(sock,NULL)) {
while(row=mysql_fetch_row(result))
{
strcpy(&b[i*BUFLEN],row[0]);
DBUG_PRINT("info",("table %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
i++;
}
}
mysql_free_result(result);
DBUG_RETURN(i);
}
/*
* Finds all servers we are connected to
* and stores them in array supplied.
* returns count of servers
*/
int
db_show_servers(char *b,int size)
{
char* bufptr;
char* buff[BUFLEN*2];
DBUG_ENTER("db_show_servers");
DBUG_PRINT("enter",("buffer: '%s', size: '%d'", b, size));
bufptr=mysql_get_host_info(sock);
// FIXME: Actually we need to escape prohibited symbols in filenames
fix_filenames(bufptr);
strcpy(b,bufptr);
DBUG_RETURN(1);
}
/*
* Finds all databases in server
* and stores them in array supplied.
* returns count of databases
*/
int
db_show_databases(char *b,int size)
{
MYSQL_RES *result;
MYSQL_ROW row;
char buff[BUFLEN];
int i=0;
DBUG_ENTER("db_show_databases");
DBUG_PRINT("enter",("buffer: '%s', size: '%d'", b, size));
result=mysql_list_dbs(sock,NULL);
while(row=mysql_fetch_row(result))
{
strcpy(&b[i*BUFLEN],row[0]);
DBUG_PRINT("info",("database %s at %x", &b[i*BUFLEN],&b[i*BUFLEN]));
i++;
}
mysql_free_result(result);
DBUG_RETURN(i);
}
void db_load_formats()
{
/* In future we should read these variables
* from configuration file/database here */
/* HTML output */
HTML.tablestart="<table>\n";
HTML.headerrowstart="<tr>";
HTML.headercellstart="<th>";
HTML.headercellseparator="</th><th>";
HTML.headercellend="</th>";
HTML.headerrowend="</tr>\n";
HTML.headerformat=0;
HTML.leftuppercorner="";
HTML.rightuppercorner="";
HTML.leftdowncorner="";
HTML.rightdowncorner="";
HTML.topcross="";
HTML.middlecross="";
HTML.bottomcross="";
HTML.leftcross="";
HTML.rightcross="";
HTML.bottomcross="";
HTML.contentrowstart="<tr>";
HTML.contentcellstart="<td>";
HTML.contentcellseparator="</td><td>";
HTML.contentcellend="</td>";
HTML.contentrowend="</tr>\n";
HTML.headerformat=0;
HTML.footerrowstart="";
HTML.footercellstart="";
HTML.footercellseparator="";
HTML.footercellend="";
HTML.footerrowend="\n";
HTML.footerformat=0;
HTML.tableend="</table>\n";
/* Nice to look mysql client like output */
Human.tablestart="\n";
Human.headerrowstart="| ";
Human.headercellstart="";
Human.headercellseparator=" | ";
Human.headercellend=" |";
Human.headerrowend="\n";
Human.headerformat=1;
Human.leftuppercorner="/=";
Human.rightuppercorner="=\\\n";
Human.leftdowncorner="\\=";
Human.rightdowncorner="=/\n";
Human.leftcross="+-";
Human.rightcross="-+\n";
Human.topcross="=T=";
Human.middlecross="-+-";
Human.bottomcross="=`=";
Human.contentrowstart="| ";
Human.contentcellstart="";
Human.contentcellseparator=" | ";
Human.contentcellend=" |";
Human.contentrowend="\n";
Human.contentformat=1;
Human.footerrowstart="";
Human.footercellstart="";
Human.footercellseparator="";
Human.footercellend="";
Human.footerrowend="\n";
Human.footerformat=1;
Human.tableend="\n";
/* Comma-separated format. For machine reading */
/* XML */
/*
tee_fprintf(PAGER,"<?xml version=\"1.0\"?>\n\n<resultset statement=\"%s\">", statement);
(void) tee_fputs("\n <row>\n", PAGER);
data=(char*) my_malloc(lengths[i]*5+1, MYF(MY_WME));
tee_fprintf(PAGER, "\t<%s>", (fields[i].name ?
(fields[i].name[0] ? fields[i].name :
" &nbsp; ") : "NULL"));
xmlencode(data, cur[i]);
tee_fprintf(PAGER, "</%s>\n", (fields[i].name ?
(fields[i].name[0] ? fields[i].name :
" &nbsp; ") : "NULL"));
</row>\n" </resultset>\n*/
}
gptr db_load_functions()
{
char *functions[]={
"database",".tables","SHOW TABLES","0",
"table",".status","SHOW TABLE STATUS FROM $table","0",
"table",".count","SELECT COUNT(*) FROM $table","0",
"table",".table","SELECT * FROM $table","0",
"table",".check","CHECK TABLE $table","0",
"table",".repair","REPAIR TABLE $table","0",
"key",".min","SELECT MIN($key) FROM $table","0",
"key",".max","SELECT MAX($key) FROM $table","0",
"key",".avg","SELECT AVG($key) FROM $table","0",
"server",".uptime","SHOW STATUS like 'Uptime'","0",
"server",".version","SELECT VERSION()","0",
"server",".execute","$*","1",
"root",".connect","CONNECT $*","0",
NULL,NULL,NULL,NULL
};
char buff[BUFLEN];
int i=0;
struct func_st func;
DBUG_ENTER("db_load_functions");
init_dynamic_array(&functions_array, sizeof(struct func_st), 4096, 1024);
while(functions[i]) {
strcpy(func.type_s, functions[i]); /* Type in string: "table"` */
strcpy(func.filename, functions[i+1]); /* Name like it appears on FS: "count" */
strcpy(func.function, functions[i+2]); /* Query: "SELECT COUNT(*) FROM `%table`" */
func.continuous= atoi(functions[i+3]); /* Query: "If command can be continued" */
if(!strcasecmp(func.type_s,"server"))
func.type=SERVER_FUNCTION;
else if(!strcasecmp(func.type_s,"table"))
func.type=TABLE_FUNCTION;
else if(!strcasecmp(func.type_s,"key"))
func.type=KEY_FUNCTION;
else if(!strcasecmp(func.type_s,"database"))
func.type=DATABASE_FUNCTION;
else if(!strcasecmp(func.type_s,"field"))
func.type=FIELD_FUNCTION;
else if(!strcasecmp(func.type_s,"root"))
func.type=ROOT_FUNCTION;
else func.type=NONE_FUNCTION;
func.length=strlen(func.filename); /* Filename length */
DBUG_PRINT("info",("func.type_s: %s",func.type_s));
DBUG_PRINT("info",("func.filename: %s",func.filename));
DBUG_PRINT("info",("func.function: %s",func.function));
DBUG_PRINT("info",("func.type: %d",func.type));
DBUG_PRINT("info",("func.continuous: %d",func.continuous));
DBUG_PRINT("info",("i: %d",i));
insert_dynamic(&functions_array,(gptr)&func);
i+=4;
}
DBUG_RETURN((gptr)&functions_array);
}

28
fs/dump.sql Normal file
View File

@ -0,0 +1,28 @@
# MySQL dump 8.12
#
# Host: localhost Database: mysqlfs
#--------------------------------------------------------
# Server version 3.23.33
#
# Table structure for table 'functions'
#
CREATE TABLE functions (
type enum('server','database','table','field','key') NOT NULL default 'server',
name char(20) NOT NULL default '',
sql char(128) NOT NULL default '',
PRIMARY KEY (type,name)
) TYPE=MyISAM;
#
# Dumping data for table 'functions'
#
INSERT INTO functions VALUES ('server','uptime','SHOW STATUS like \'Uptime\'');
INSERT INTO functions VALUES ('server','version','SELECT VERSION()');
INSERT INTO functions VALUES ('table','count','SELECT COUNT(*) FROM `%table`');
INSERT INTO functions VALUES ('key','min','SELECT MIN(%key) FROM `%table`');
INSERT INTO functions VALUES ('key','max','SELECT MAX(%key) FROM `%table`');
INSERT INTO functions VALUES ('key','avg','SELECT AVG(%key) FROM `%table`');

35661
fs/korbit-kernel-2.4.1-patch Normal file

File diff suppressed because it is too large Load Diff

153
fs/libmysqlfs.c Normal file
View File

@ -0,0 +1,153 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "libmysqlfs.h"
int search_and_replace(char *search, char* replace, char* string)
{
char buff[1024];
int found=0;
char *ptr1;
const char *ptr2=buff;
char *strptr=string;
DBUG_ENTER("search_and_replace");
DBUG_PRINT("enter",("search: '%s' replace:'%s' string:'%s'",search,replace,string));
strcpy(buff,string);
while(ptr1=strstr(ptr2,search))
{
strncpy(strptr,ptr2,ptr1-buff);
strptr+=ptr1-buff;
ptr2+=ptr1-buff+strlen(search);
strcpy(strptr,replace);
strptr+=strlen(replace);
found++;
}
DBUG_RETURN(found);
}
int show_functions(char *b, function_type type)
{
int i=0,j=0;
struct func_st func;
DBUG_ENTER("show_functions");
get_dynamic(&functions_array,(gptr)&func,i);
while(func.length) {
if (func.type == type)
strcpy(&b[j++*BUFLEN],func.filename);
get_dynamic(&functions_array,(gptr)&func,++i);
}
DBUG_RETURN(j);
}
struct func_st * check_if_function(char *name, function_type type)
{
int pathlen;
int j,i=0, len;
static struct func_st function;
char buffer[BUFLEN];
DBUG_ENTER("check_if_function");
DBUG_PRINT("enter",("name: '%s' type: '%d'", name, type));
pathlen=strlen(name);
/* We try to compare last element in path to function names */
get_dynamic(&functions_array,(gptr)&function,i);
while(function.length) {
function.continuous ?
(j=!strncasecmp(function.filename, name, function.length))
: (j=!strcasecmp(function.filename,name));
if(j) { /* This happens when function was matched */
DBUG_PRINT("info",("Function %s detected!",function.filename));
break;
}
get_dynamic(&functions_array,(gptr)&function,++i);
}
/* Copy path to buffer and trip function name (if found) from it */
if(function.length != 0)
{
DBUG_RETURN(&function);
} else {
DBUG_RETURN(0);
}
}
/*
* parse - splits "path" into different variables
* in way "/server/database/table/(field|key)/(value|function)". If path is shorter,
* then other fields will be NULL. If path is longer than four levels or
* shorter than one level, FS_NOTEXIST is returned.
*/
int parse(const char * path, char *server, char * database, char *table,
char* field, char* value, struct func_st **funce)
{
char buffer[BUFLEN];
char *p=buffer;
char *x;
int len;
DBUG_ENTER("parse");
DBUG_PRINT("enter",("path: '%s'", path));
*server=*database=*table=*field=*value='\0';
/* Search for first slash and drop it */
strcpy(buffer,path);
x=strtok_r(p,"/",&p);
if(x)
{
strcpy(server,x); /* First argument is server name */
if(*p)
strcpy(database,strtok_r(p,"/",&p)); /* Second is database */
if(p && *p)
strcpy(table ,strtok_r(p,"/",&p)); /* Third is table name */
if(p && *p)
strcpy(field ,strtok_r(p,"/",&p)); /* Fourth is field or key name */
if(p && *p)
strcpy(value ,strtok_r(p,"/",&p)); /* Fifth is field/key value or function */
}
/* We have to find if last argument is function,
* In which case we clear it
*/
if(*value) {
*funce=check_if_function(value,VALUE_FUNCTION);
if(*funce) *value='\0';
} else if (*field) {
*funce=check_if_function(field,FIELD_FUNCTION);
if(*funce) *field='\0';
} else if (*table) {
*funce=check_if_function(table,TABLE_FUNCTION);
if(*funce) *table='\0';
} else if (*database) {
*funce=check_if_function(database,DATABASE_FUNCTION);
if(*funce) *database='\0';
} else if (*server) {
*funce=check_if_function(server,SERVER_FUNCTION);
if(*funce) *server='\0';
} else
*funce=NULL;
DBUG_PRINT("info",("path: '%s', server: '%s', db: '%s', table: '%s', field: '%s', value: '%s', function: '%x'",
buffer, server, database, table, field, value, funce ));
if(p && *p) /* Something is in buffer - too deep in levels */
DBUG_RETURN(-1)
else
DBUG_RETURN(0)
}

81
fs/libmysqlfs.h Normal file
View File

@ -0,0 +1,81 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "CorbaFS.h"
#include <global.h>
#include <my_sys.h>
#include <m_string.h>
#include <m_ctype.h>
#include "mysql.h"
#define BUFLEN 1024
#define MAXDIRS 1024
typedef enum {
FUNC_NONE,
FUNC_SERVER_UPTIME,
FUNC_SERVER_THREADS,
FUNC_SERVER_VERSION,
FUNC_DATABASE_CREATED,
FUNC_TABLE_COUNT,
FUNC_TABLE_CREATED,
FUNC_FIELD_LENGTH,
FUNC_KEY_AVG,
FUNC_KEY_SUM,
FUNC_KEY_MAX,
FUNC_KEY_MIN
} func_enum;
typedef enum {
NONE_FUNCTION,
ROOT_FUNCTION,
SERVER_FUNCTION,
DATABASE_FUNCTION,
TABLE_FUNCTION,
KEY_FUNCTION,
FIELD_FUNCTION,
VALUE_FUNCTION
} function_type;
struct func_st {
char type_s[20];
char filename[20];
char function[80];
function_type type;
int length;
my_bool continuous;
} ;
int parse(const char* path,
char* root,
char* database,
char* table,
char* key,
char* field,
struct func_st **func
);
gptr db_load_functions();
int db_function(char *b,const char *server, const char *database,const char *table,const char *field,
const char *value, const char *path, struct func_st *function);
int fix_filenames(char *buf);
DYNAMIC_ARRAY functions_array;

5
fs/my.cnf Normal file
View File

@ -0,0 +1,5 @@
[mysqlcorbafs]
socket=/var/lib/mysql/mysql.sock
host=127.0.0.1
user=root
#password=xxxxxx

992
fs/mysqlcorbafs.c Normal file
View File

@ -0,0 +1,992 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
*
* fsck.mysql
*/
#include "libmysqlfs.h"
#include "mysqlcorbafs.h"
#include <getopt.h>
#define MAXPATHLEN 256
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <my_sys.h>
static long inodeNum;
extern DYNAMIC_ARRAY functions_array;
enum options {OPT_FTB=256, OPT_LTB, OPT_ENC, OPT_O_ENC, OPT_ESC, OPT_KEYWORDS,
OPT_LOCKS, OPT_DROP, OPT_OPTIMIZE, OPT_DELAYED, OPT_TABLES,
OPT_CHARSETS_DIR, OPT_DEFAULT_CHARSET};
CHANGEABLE_VAR changeable_vars[] = {
{ "max_allowed_packet", (long*) &max_allowed_packet,24*1024*1024,4096,
24*1024L*1024L,MALLOC_OVERHEAD,1024},
{ "net_buffer_length", (long*) &net_buffer_length,1024*1024L-1025,4096,
24*1024L*1024L,MALLOC_OVERHEAD,1024},
{ 0, 0, 0, 0, 0, 0, 0}
};
CORBA_ORB orb;
PortableServer_POA poa;
CORBA_Environment *ev;
PortableServer_ObjectId *objid;
static my_bool verbose=0,opt_compress=0,extended_insert=0, lock_tables=0,
opt_quoted=0, opt_lock=0, opt_delayed=0, ignore_errors=0;
gptr fptr;
static const char *load_default_groups[]= { "mysqlcorbafs","client",0 };
static char *default_charset, *current_host, *current_user, *opt_password,
*path,*fields_terminated=0, *lines_terminated=0, *enclosed=0,
*opt_enclosed=0, *escaped=0;
static struct option long_options[] =
{
{"add-locks", no_argument, 0,OPT_LOCKS},
{"character-sets-dir",required_argument,0, OPT_CHARSETS_DIR},
{"compress", no_argument, 0, 'C'},
{"database",required_argument, 0, 'D'},
{"debug",optional_argument, 0, '#'},
{"default-character-set", required_argument, 0, OPT_DEFAULT_CHARSET},
{"delayed-insert",no_argument, 0, OPT_DELAYED},
{"fields-terminated-by", required_argument, 0, (int) OPT_FTB},
{"fields-enclosed-by", required_argument,0, (int) OPT_ENC},
{"fields-optionally-enclosed-by", required_argument, 0, (int) OPT_O_ENC},
{"fields-escaped-by", required_argument,0, (int) OPT_ESC},
{"functions",required_argument, 0, 'f'},
{"help", no_argument, 0,'?'},
{"host", required_argument,0, 'h'},
{"lines-terminated-by", required_argument, 0, (int) OPT_LTB},
{"lock-tables", no_argument, 0, 'l'},
{"no-data", no_argument, 0, 'd'},
{"password", optional_argument, 0, 'p'},
#ifdef __WIN__
{"pipe",no_argument,0, 'W'},
#endif
{"port", required_argument,0, 'P'},
// {"quick", no_argument,0, 'q'},
{"quote-names",no_argument,0, 'Q'},
{"set-variable",required_argument,0, 'O'},
{"socket", required_argument,0, 'S'},
#include "sslopt-longopts.h"
#ifndef DONT_ALLOW_USER_CHANGE
{"user", required_argument,0, 'u'},
#endif
{"verbose", no_argument,0, 'v'},
{"version", no_argument,0, 'V'},
{0, 0, 0, 0}
};
/*
void
print_table_data(MYSQL_RES *result)
{
String separator(256);
MYSQL_ROW cur;
MYSQL_FIELD *field;
bool *num_flag;
num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result));
if (info_flag)
{
print_field_types(result);
mysql_field_seek(result,0);
}
separator.copy("+",1);
while ((field = mysql_fetch_field(result)))
{
uint length=skip_column_names ? 0 : (uint) strlen(field->name);
if (quick)
length=max(length,field->length);
else
length=max(length,field->max_length);
if (length < 4 && !IS_NOT_NULL(field->flags))
length=4; // Room for "NULL"
field->max_length=length+1;
separator.fill(separator.length()+length+2,'-');
separator.append('+');
}
tee_puts(separator.c_ptr(), PAGER);
if (!skip_column_names)
{
mysql_field_seek(result,0);
(void) tee_fputs("|", PAGER);
for (uint off=0; (field = mysql_fetch_field(result)) ; off++)
{
tee_fprintf(PAGER, " %-*s|",min(field->max_length,MAX_COLUMN_LENGTH),
field->name);
num_flag[off]= IS_NUM(field->type);
}
(void) tee_fputs("\n", PAGER);
tee_puts(separator.c_ptr(), PAGER);
}
while ((cur = mysql_fetch_row(result)))
{
(void) tee_fputs("|", PAGER);
mysql_field_seek(result,0);
for (uint off=0 ; off < mysql_num_fields(result); off++)
{
const char *str=cur[off] ? cur[off] : "NULL";
field = mysql_fetch_field(result);
uint length=field->max_length;
if (length > MAX_COLUMN_LENGTH)
{
tee_fputs(str,PAGER); tee_fputs(" |",PAGER);
}
else
tee_fprintf(PAGER, num_flag[off] ? "%*s |" : " %-*s|",
length, str);
}
(void) tee_fputs("\n", PAGER);
}
tee_puts(separator.c_ptr(), PAGER);
my_afree((gptr) num_flag);
}
void
print_table_data_html(MYSQL_RES *result)
{
MYSQL_ROW cur;
MYSQL_FIELD *field;
mysql_field_seek(result,0);
(void) tee_fputs("<TABLE BORDER=1><TR>", PAGER);
if (!skip_column_names)
{
while((field = mysql_fetch_field(result)))
{
tee_fprintf(PAGER, "<TH>%s</TH>", (field->name ?
(field->name[0] ? field->name :
" &nbsp; ") : "NULL"));
}
(void) tee_fputs("</TR>", PAGER);
}
while ((cur = mysql_fetch_row(result)))
{
(void) tee_fputs("<TR>", PAGER);
for (uint i=0; i < mysql_num_fields(result); i++)
{
ulong *lengths=mysql_fetch_lengths(result);
(void) tee_fputs("<TD>", PAGER);
safe_put_field(cur[i],lengths[i]);
(void) tee_fputs("</TD>", PAGER);
}
(void) tee_fputs("</TR>", PAGER);
}
(void) tee_fputs("</TABLE>", PAGER);
}
void
print_table_data_xml(MYSQL_RES *result)
{
MYSQL_ROW cur;
MYSQL_FIELD *fields;
mysql_field_seek(result,0);
char *statement;
statement=(char*) my_malloc(strlen(glob_buffer.ptr())*5+1, MYF(MY_WME));
xmlencode(statement, (char*) glob_buffer.ptr());
(void) my_chomp(strend(statement));
tee_fprintf(PAGER,"<?xml version=\"1.0\"?>\n\n<resultset statement=\"%s\">", statement);
my_free(statement,MYF(MY_ALLOW_ZERO_PTR));
fields = mysql_fetch_fields(result);
while ((cur = mysql_fetch_row(result)))
{
(void) tee_fputs("\n <row>\n", PAGER);
for (uint i=0; i < mysql_num_fields(result); i++)
{
char *data;
ulong *lengths=mysql_fetch_lengths(result);
data=(char*) my_malloc(lengths[i]*5+1, MYF(MY_WME));
tee_fprintf(PAGER, "\t<%s>", (fields[i].name ?
(fields[i].name[0] ? fields[i].name :
" &nbsp; ") : "NULL"));
xmlencode(data, cur[i]);
safe_put_field(data, strlen(data));
tee_fprintf(PAGER, "</%s>\n", (fields[i].name ?
(fields[i].name[0] ? fields[i].name :
" &nbsp; ") : "NULL"));
my_free(data,MYF(MY_ALLOW_ZERO_PTR));
}
(void) tee_fputs(" </row>\n", PAGER);
}
(void) tee_fputs("</resultset>\n", PAGER);
}
void
print_table_data_vertically(MYSQL_RES *result)
{
MYSQL_ROW cur;
uint max_length=0;
MYSQL_FIELD *field;
while ((field = mysql_fetch_field(result)))
{
uint length=(uint) strlen(field->name);
if (length > max_length)
max_length= length;
field->max_length=length;
}
mysql_field_seek(result,0);
for (uint row_count=1; (cur= mysql_fetch_row(result)); row_count++)
{
mysql_field_seek(result,0);
tee_fprintf(PAGER,
"*************************** %d. row ***************************\n", row_count);
for (uint off=0; off < mysql_num_fields(result); off++)
{
field= mysql_fetch_field(result);
tee_fprintf(PAGER, "%*s: ",(int) max_length,field->name);
tee_fprintf(PAGER, "%s\n",cur[off] ? (char*) cur[off] : "NULL");
}
}
}
*/
static my_bool test_if_special_chars(const char *str)
{
for ( ; *str ; str++)
if (!isvar(*str) && *str != '$')
return 1;
return 0;
} /* test_if_special_chars */
char *quote_name(char *name, char *buff)
{
char *end;
DBUG_ENTER("quote_name");
if (!opt_quoted && !test_if_special_chars(name))
return name;
buff[0]=QUOTE_CHAR;
*end=strmov(buff+1,name);
end[0]=QUOTE_CHAR;
end[1]=0;
DBUG_RETURN(buff);
} /* quote_name */
/*
* Allow the user to specify field terminator strings like:
* "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
* This is done by doubleing ' and add a end -\ if needed to avoid
* syntax errors from the SQL parser.
*/
char *field_escape(char *to,const char *from,uint length)
{
const char *end;
uint end_backslashes=0;
DBUG_ENTER("field_escape");
{
*to++= *from;
if (*from == '\\')
end_backslashes^=1; /* find odd number of backslashes */
else {
if (*from == '\'' && !end_backslashes)
*to++= *from; /* We want a duplicate of "'" for MySQL */
end_backslashes=0;
}
}
/* Add missing backslashes if user has specified odd number of backs.*/
if (end_backslashes)
*to++= '\\';
DBUG_RETURN(to);
} /* field_escape */
void safe_exit(int error)
{
if (!first_error)
first_error= error;
if (ignore_errors)
return;
if (sock)
mysql_close(sock);
exit(error);
}
/* safe_exit */
/*
* ** DBerror -- prints mysql error message and exits the program.
*/
void DBerror(MYSQL *mysql, const char *when)
{
DBUG_ENTER("DBerror");
my_printf_error(0,"Got error: %d: %s %s", MYF(0),
mysql_errno(mysql), mysql_error(mysql), when);
safe_exit(EX_MYSQLERR);
DBUG_VOID_RETURN;
} /* DBerror */
void print_version(void)
{
printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,CORBAFS_VERSION,
MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
} /* print_version */
void usage(void)
{
uint i;
print_version();
puts("By T<>nu Samuel. Some code is partially from other geeks around the world");
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
puts("Dumping definition and data mysql database or table");
printf("Usage: %s [OPTIONS]\n", my_progname);
printf("\n\
-#, --debug=... Output debug log. Often this is 'd:t:o,filename`.\n\
--character-sets-dir=...\n\
Directory where character sets are\n\
-?, --help Display this help message and exit.\n\
-c, --complete-insert Use complete insert statements.\n\
-C, --compress Use compression in server/client protocol.\n\
--default-character-set=...\n\
Set the default character set\n\
-e, --extended-insert Allows utilization of the new, much faster\n\
INSERT syntax.\n\
--add-locks Add locks around insert statements.\n\
--allow-keywords Allow creation of column names that are keywords.\n\
--delayed-insert Insert rows with INSERT DELAYED.\n\
-f, --force Continue even if we get an sql-error.\n\
-h, --host=... Connect to host.\n");
puts("\
-l, --lock-tables Lock all tables for read.\n\
-t, --no-create-info Don't write table creation info.\n\
-d, --no-data No row information.\n\
-O, --set-variable var=option\n\
give a variable a value. --help lists variables\n\
-p, --password[=...] Password to use when connecting to server.\n\
If password is not given it's solicited on the tty.\n");
#ifdef __WIN__
puts("-W, --pipe Use named pipes to connect to server");
#endif
printf("\
-P, --port=... Port number to use for connection.\n\
-q, --quick Don't buffer query, dump directly to stdout.\n\
-S, --socket=... Socket file to use for connection.\n\
--tables Overrides option --databases (-B).\n");
#include "sslopt-usage.h"
#ifndef DONT_ALLOW_USER_CHANGE
printf("\
-u, --user=# User for login if not current user.\n");
#endif
printf("\
-v, --verbose Print info about the various stages.\n\
-V, --version Output version information and exit.\n\
");
print_defaults("my",load_default_groups);
printf("\nPossible variables for option --set-variable (-O) are:\n");
for (i=0 ; changeable_vars[i].name ; i++)
printf("%-20s current value: %lu\n",
changeable_vars[i].name,
(ulong) *changeable_vars[i].varptr);
} /* usage */
static int get_options(int *argc,char ***argv)
{
int c,option_index;
my_bool tty_password=0;
DBUG_ENTER("get_options");
load_defaults("my",load_default_groups,argc,argv);
set_all_changeable_vars(changeable_vars);
while ((c=getopt_long(*argc,*argv,"#::p::h:u:O:P:S:T:EBaAcCdefFlnqtvVw:?Ix",
long_options, &option_index)) != EOF)
{
switch(c) {
case 'e':
extended_insert=1;
break;
case OPT_DEFAULT_CHARSET:
default_charset= optarg;
break;
case OPT_CHARSETS_DIR:
charsets_dir= optarg;
break;
ignore_errors=1;
break;
case 'h':
my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
current_host=my_strdup(optarg,MYF(MY_WME));
break;
#ifndef DONT_ALLOW_USER_CHANGE
case 'u':
current_user=optarg;
break;
#endif
case 'O':
if (set_changeable_var(optarg, changeable_vars))
{
usage();
return(1);
}
break;
case 'p':
if (optarg)
{
char *start=optarg;
my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
opt_password=my_strdup(optarg,MYF(MY_FAE));
while (*optarg) *optarg++= 'x'; /* Destroy argument */
if (*start)
start[1]=0; /* Cut length of argument */
} else
tty_password=1;
break;
case 'P':
opt_mysql_port= (unsigned int) atoi(optarg);
break;
case 'S':
opt_mysql_unix_port= optarg;
break;
case 'W':
#ifdef __WIN__
opt_mysql_unix_port=MYSQL_NAMEDPIPE;
#endif
break;
case 'T':
path= optarg;
break;
case '#':
DBUG_PUSH(optarg ? optarg : "d:t:o");
break;
case 'C':
opt_compress=1;
break;
case 'l': lock_tables=1; break;
case 'Q': opt_quoted=1; break;
case 'v': verbose=1; break;
case 'V': print_version(); exit(0);
default:
fprintf(stderr,"%s: Illegal option character '%c'\n",my_progname,opterr);
/* Fall throught */
case 'I':
case '?':
usage();
exit(0);
case (int) OPT_FTB:
fields_terminated= optarg;
break;
case (int) OPT_LTB:
lines_terminated= optarg;
break;
case (int) OPT_ENC:
enclosed= optarg;
break;
case (int) OPT_O_ENC:
opt_enclosed= optarg;
break;
case (int) OPT_ESC:
escaped= optarg;
break;
case (int) OPT_LOCKS:
opt_lock=1;
break;
case (int) OPT_OPTIMIZE:
extended_insert=opt_lock=lock_tables=1;
break;
case (int) OPT_DELAYED:
opt_delayed=1;
break;
#include "sslopt-case.h"
}
}
if (opt_delayed)
opt_lock=0; /* Can't have lock with delayed */
if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
fields_terminated))
{
fprintf(stderr, "%s: You must use option --tab with --fields-...\n", my_progname);
return(1);
}
if (enclosed && opt_enclosed)
{
fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname);
return(1);
}
if (default_charset)
{
if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
exit(1);
}
(*argc)-=optind;
(*argv)+=optind;
if (tty_password)
opt_password=get_tty_password(NullS);
DBUG_RETURN(0);
} /* get_options */
/*** epv structures ***/
static PortableServer_ServantBase__epv impl_Inode_base_epv = {
NULL, /* _private data */
NULL, /* finalize routine */
NULL, /* default_POA routine */
};
static POA_CorbaFS_Inode__epv impl_Inode_epv = {
NULL, /* _private */
(gpointer) & impl_Inode_getStatus,
(gpointer) & impl_Inode_readpage,
(gpointer) & impl_Inode_release,
};
static PortableServer_ServantBase__epv impl_FileSystem_base_epv = {
NULL, /* _private data */
NULL, /* finalize routine */
NULL, /* default_POA routine */
};
static POA_CorbaFS_FileSystem__epv impl_FileSystem_epv = {
NULL, /* _private */
(gpointer) & impl_FileSystem_getInode,
(gpointer) & impl_FileSystem_readdir,
(gpointer) & impl_FileSystem_readlink,
};
/*** vepv structures ***/
static POA_CorbaFS_Inode__vepv impl_Inode_vepv = {
&impl_Inode_base_epv,
&impl_Inode_epv,
};
static POA_CorbaFS_FileSystem__vepv impl_FileSystem_vepv = {
&impl_FileSystem_base_epv,
&impl_FileSystem_epv,
};
/*** Stub implementations ***/
static CorbaFS_Inode
impl_Inode__create(PortableServer_POA poa, CORBA_Environment * ev)
{
CorbaFS_Inode retval;
impl_POA_CorbaFS_Inode *newservant;
PortableServer_ObjectId *objid;
DBUG_ENTER("impl_Inode__create");
newservant = g_new0(impl_POA_CorbaFS_Inode, 1);
newservant->servant.vepv = &impl_Inode_vepv;
newservant->poa = poa;
POA_CorbaFS_Inode__init((PortableServer_Servant) newservant, ev);
objid = PortableServer_POA_activate_object(poa, newservant, ev);
CORBA_free(objid);
retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
DBUG_RETURN(retval);
}
static void
impl_Inode__destroy(impl_POA_CorbaFS_Inode * servant,
CORBA_Environment * ev)
{
PortableServer_ObjectId *objid;
DBUG_ENTER("impl_Inode__destroy");
objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
PortableServer_POA_deactivate_object(servant->poa, objid, ev);
CORBA_free(objid);
POA_CorbaFS_Inode__fini((PortableServer_Servant) servant, ev);
g_free(servant);
DBUG_VOID_RETURN;
}
static void
impl_Inode_getStatus(impl_POA_CorbaFS_Inode * servant,
CORBA_unsigned_short * mode,
CORBA_unsigned_long * uid,
CORBA_unsigned_long * gid,
CORBA_unsigned_long * size,
CORBA_unsigned_long * inodeNum,
CORBA_unsigned_short * numLinks,
CORBA_long * atime,
CORBA_long * mtime,
CORBA_long * ctime, CORBA_Environment * ev)
{
struct stat buf;
char
server[BUFLEN],
database[BUFLEN],
table[BUFLEN],
key[BUFLEN],
field[BUFLEN],
value[BUFLEN];
struct func_st *func;
DBUG_ENTER("impl_Inode_getStatus");
DBUG_PRINT("enter",("path: '%s', mode: '%o', uid: '%d', gid: '%d', size: '%d',
inodeNum: '%d', numLinks: '%d', atime: '%d',mtime: '%d', ctime: '%d'",
servant->path, mode, uid, gid, size, inodeNum, numLinks, atime, mtime, ctime));
DBUG_PRINT("info",("func: %x",&func));
if(parse(servant->path, server, database, table, field, value, &func)>0)
{
DBUG_PRINT("info",("ENOENT"));
*mode=0;
} else if (func != NULL){
DBUG_PRINT("info",("func: %x",&func));
DBUG_PRINT("info",("Argument is function at %x, returning S_IFREG",func));
*mode = S_IFREG; // File
} else if (*field){
DBUG_PRINT("info",("Argument is file, returning S_IFREG"));
*mode = S_IFREG; // File
} else {
DBUG_PRINT("info",("Argument is directory, returning S_IFDIR"));
*mode = S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH ; // Dir
}
*mode |= S_IRUSR | S_IRGRP | S_IROTH;
*uid = 0;
*gid = 0;
*size = 4096;
*inodeNum = servant->inodeNum;
*numLinks = 1;
*atime = 3;
*mtime = 2;
*ctime = 1;
// lstat(servant->path, &buf);
// *mode = buf.st_mode;
/* *uid = buf.st_uid;
*gid = buf.st_gid;
*size = buf.st_size;
*inodeNum = buf.st_ino;
*numLinks = buf.st_nlink;
*atime = buf.st_atime;
*mtime = buf.st_mtime;
*ctime = buf.st_ctime;*/
DBUG_VOID_RETURN;
}
static void
impl_Inode_readpage(impl_POA_CorbaFS_Inode * servant,
CorbaFS_Buffer ** buffer,
CORBA_long size,
CORBA_long offset, CORBA_Environment * ev)
{
int type;
int fd = -1, c = 0;
int res;
char
server[BUFLEN],
database[BUFLEN],
table[BUFLEN],
key[BUFLEN],
field[BUFLEN],
value[BUFLEN];
struct func_st *func;
DBUG_ENTER("impl_Inode_readpage");
DBUG_PRINT("enter",("path: '%s'", servant->path));
*buffer = CorbaFS_Buffer__alloc();
(*buffer)->_maximum = size;
(*buffer)->_buffer = CORBA_octet_allocbuf(size);
printf("requested to read %d bytes\n",size);
memset((*buffer)->_buffer, size, 0);
type = parse(servant->path, server, database, table, field, value, &func);
if (func != NULL)
res=db_function((*buffer)->_buffer, server, database, table, field, value, servant->path, func);
else
res=db_show_field((*buffer)->_buffer, database, table, field, path, value);
if(res>0)
(*buffer)->_length = strlen((*buffer)->_buffer);
else
(*buffer)->_length = 0;
/*
fd = open(servant->path, O_RDONLY);
printf("Inode_readpage : fd = %d\n", fd);
lseek(fd, offset, SEEK_SET);
c = read(fd, (*buffer)->_buffer, size);
printf("Inode_readpage : read %d bytes\n", c);
(*buffer)->_length = c;
close(fd);
*/
DBUG_VOID_RETURN;
}
static void
impl_Inode_release(impl_POA_CorbaFS_Inode * servant,
CORBA_Environment * ev)
{
DBUG_ENTER("impl_Inode_readpage");
DBUG_PRINT("enter",("path: '%s'", servant->path));
DBUG_VOID_RETURN;
}
/*
* This function is called when we get mounted
*/
CorbaFS_FileSystem
impl_FileSystem__create(PortableServer_POA poa,
CORBA_Environment * ev)
{
CorbaFS_FileSystem retval;
impl_POA_CorbaFS_FileSystem *newservant;
PortableServer_ObjectId *objid;
DBUG_ENTER("impl_FileSystem__create");
newservant = g_new0(impl_POA_CorbaFS_FileSystem, 1);
newservant->servant.vepv = &impl_FileSystem_vepv;
newservant->poa = poa;
POA_CorbaFS_FileSystem__init((PortableServer_Servant) newservant, ev);
objid = PortableServer_POA_activate_object(poa, newservant, ev);
CORBA_free(objid);
retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
DBUG_RETURN(retval);
}
/*
* This function is called when we get unmounted
*/
static void
impl_FileSystem__destroy(impl_POA_CorbaFS_FileSystem * servant,
CORBA_Environment * ev)
{
PortableServer_ObjectId *objid;
DBUG_ENTER("impl_FileSystem__destroy");
objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
PortableServer_POA_deactivate_object(servant->poa, objid, ev);
CORBA_free(objid);
POA_CorbaFS_FileSystem__fini((PortableServer_Servant) servant, ev);
g_free(servant);
DBUG_VOID_RETURN;
}
static CorbaFS_Inode
impl_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant,
CORBA_char * path, CORBA_Environment * ev)
{
CorbaFS_Inode retval;
impl_POA_CorbaFS_Inode *inode;
char
database[BUFLEN],
table[BUFLEN],
key[BUFLEN],
field[BUFLEN];
char buffer[MAXDIRS][BUFLEN];
int c;
DBUG_ENTER("impl_FileSystem_getInode");
DBUG_PRINT("enter",("path: '%s'", path));
//FIXME: We should verify the existense of file/dir here
//
retval = impl_Inode__create(servant->poa, ev);
inode = PortableServer_POA_reference_to_servant( servant->poa, retval, ev );
inode->path = CORBA_string_dup(path);
//FIXME: inodeNum Generation goes here
//
inode->inodeNum= inodeNum++;
#if 0
inode->mode = 0040777; /* world-readable directory */
inode->uid = 0;
inode->gid = 0;
inode->size = 4096;
inode->inodeNum = inodeNum++;
inode->numLinks = 1;
inode->atime = 0;
inode->mtime = 100;
inode->ctime = 10000;
#endif
DBUG_RETURN(retval);
}
static CorbaFS_DirEntSeq *
impl_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant,
CORBA_char * path, CORBA_Environment * ev)
{
CorbaFS_DirEntSeq *retval;
CorbaFS_dirent *dirent;
struct func_st *func;
int c, c2,i;
char
server[BUFLEN],
table[BUFLEN],
field[BUFLEN],
value[BUFLEN],
buffer[MAXDIRS][BUFLEN],
buffer2[MAXDIRS][BUFLEN],
database[BUFLEN];
DBUG_ENTER("impl_FileSystem_readdir");
DBUG_PRINT("enter",("path: '%s'", path));
retval = CorbaFS_DirEntSeq__alloc();
retval->_maximum = 0;
retval->_length = 0;
parse(path, server, database, table, field, value, &func);
if (func != NULL) {
c2 = db_function((char *)buffer, server, database, table, field, value, path, func);
} else if(!*server) {
c2 = db_show_servers(buffer2,MAXDIRS);
c = show_functions((char *)buffer, ROOT_FUNCTION);
} else if(!*database) {
c2 = db_show_databases(buffer2,MAXDIRS);
c = show_functions((char *)buffer, SERVER_FUNCTION);
} else if(!*table){
c2 = db_show_tables(buffer2, database);
c = show_functions((char *)buffer, DATABASE_FUNCTION);
} else if(!*field){
c2 = db_show_primary_keys(buffer2, database,table);
if(c2>=0) {
c = show_functions((char *)buffer, TABLE_FUNCTION);
}
} else {
c2 = db_show_fields(buffer2, database, table, field);
c = show_functions((char *)buffer, FIELD_FUNCTION);
c = show_functions((char *)buffer, KEY_FUNCTION);
}
if(c2 < 0)
c=c2=0; // Error occured in database routines
/* Allocate space to hold all found entries plus "." and ".." */
retval->_maximum = c + c2 + 2;
retval->_buffer = CORBA_sequence_CorbaFS_dirent_allocbuf(retval->_maximum) ;
dirent = retval->_buffer;
i = 0;
while (i < c) {
long inode = 123L;
dirent[i].inode = inode;
dirent[i].name = CORBA_string_dup(buffer[i]);
i++;
}
i = 0;
while (i < c2) {
long inode = 123L;
dirent[c+i].inode = inode;
dirent[c+i].name = CORBA_string_dup(buffer2[i]);
i++;
}
dirent[c+i].inode = 123L;
dirent[c+i].name = CORBA_string_dup(".");
i++;
dirent[c+i].inode = 123L;
dirent[c+i].name = CORBA_string_dup("..");
retval->_length = retval->_maximum;
DBUG_RETURN(retval);
}
static CORBA_char *
impl_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant,
CORBA_char * filename,
CORBA_Environment * ev)
{
CORBA_char *retval = CORBA_OBJECT_NIL;
char tmp[MAXPATHLEN + 1];
int len;
DBUG_ENTER("impl_FileSystem_readlink");
DBUG_PRINT("enter",("path: '%s'", filename));
/* len = readlink(filename, tmp, MAXPATHLEN);
if (len != -1)
{
tmp[len] = '\0';
retval = CORBA_string_dup(tmp);
}
printf("%s\n", retval);
*/
DBUG_RETURN(retval);
}
int fix_filenames(char *buf)
{
int i;
for(i=0; i<strlen(buf);i++)
if(buf[i]=='/')
buf[i]='_';
}
int main(int argc, char *argv[]) {
CorbaFS_FileSystem fs;
impl_POA_CorbaFS_FileSystem *fs_impl;
FILE *f;
PortableServer_POAManager pm;
DBUG_ENTER("main");
DBUG_PROCESS(argv[0]);
ev = g_new0(CORBA_Environment,1);
CORBA_exception_init(ev);
orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);
MY_INIT(argv[0]);
/*
** Check out the args
*/
if (get_options(&argc, &argv))
{
my_end(0);
exit(EX_USAGE);
}
if (db_connect(current_host, current_user, opt_password))
exit(EX_MYSQLERR);
fptr = db_load_functions();
db_load_formats();
poa = (PortableServer_POA)
CORBA_ORB_resolve_initial_references(orb, "RootPOA", ev);
fs = impl_FileSystem__create(poa, ev);
pm = PortableServer_POA__get_the_POAManager(poa, ev);
PortableServer_POAManager_activate(pm, ev);
fs_impl = PortableServer_POA_reference_to_servant( poa, fs, ev );
objid = PortableServer_POA_servant_to_id( poa, fs_impl, ev );
printf("CorbaFS-server:\n%s\n", CORBA_ORB_object_to_string(orb, fs, ev));
f=fopen("/tmp/mysqlcorbafs.ior","w");
fputs(CORBA_ORB_object_to_string(orb, fs, ev),f);
fclose(f);
CORBA_ORB_run(orb, ev);
db_disconnect(current_host);
return 0;
}

159
fs/mysqlcorbafs.h Normal file
View File

@ -0,0 +1,159 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "CorbaFS.h"
#include <global.h>
#include <my_sys.h>
#include <m_string.h>
#include <m_ctype.h>
#include "mysql.h"
#define QUOTE_CHAR '`'
/* Exit codes */
#define EX_USAGE 1
#define EX_MYSQLERR 2
#define EX_CONSCHECK 3
#define EX_EOM 4
#define CORBAFS_VERSION "0.01"
typedef struct
{
POA_CorbaFS_Inode servant;
PortableServer_POA poa;
CORBA_char *path;
CORBA_unsigned_long inodeNum;
#if 0
CORBA_unsigned_short mode;
CORBA_unsigned_long uid;
CORBA_unsigned_long gid;
CORBA_unsigned_long size;
CORBA_unsigned_short numLinks;
CORBA_long atime;
CORBA_long mtime;
CORBA_long ctime;
#endif
}
impl_POA_CorbaFS_Inode;
typedef struct
{
POA_CorbaFS_FileSystem servant;
PortableServer_POA poa;
}
impl_POA_CorbaFS_FileSystem;
/*** Implementation stub prototypes ***/
CorbaFS_FileSystem
impl_FileSystem__create(PortableServer_POA poa, CORBA_Environment * ev);
static void
impl_Inode__destroy(impl_POA_CorbaFS_Inode * servant,
CORBA_Environment * ev);
static void
impl_Inode_getStatus(impl_POA_CorbaFS_Inode * servant,
CORBA_unsigned_short * mode,
CORBA_unsigned_long * uid,
CORBA_unsigned_long * gid,
CORBA_unsigned_long * size,
CORBA_unsigned_long * inodeNum,
CORBA_unsigned_short * numLinks,
CORBA_long * atime,
CORBA_long * mtime,
CORBA_long * ctime, CORBA_Environment * ev);
static void
impl_Inode_readpage(impl_POA_CorbaFS_Inode * servant,
CorbaFS_Buffer ** buffer,
CORBA_long size,
CORBA_long offset, CORBA_Environment * ev);
static void
impl_Inode_release(impl_POA_CorbaFS_Inode * servant,
CORBA_Environment * ev);
static void impl_FileSystem__destroy(impl_POA_CorbaFS_FileSystem *
servant, CORBA_Environment * ev);
static CorbaFS_Inode
impl_FileSystem_getInode(impl_POA_CorbaFS_FileSystem * servant,
CORBA_char * path, CORBA_Environment * ev);
static CorbaFS_DirEntSeq *
impl_FileSystem_readdir(impl_POA_CorbaFS_FileSystem * servant,
CORBA_char * path,
CORBA_Environment * ev);
static CORBA_char *
impl_FileSystem_readlink(impl_POA_CorbaFS_FileSystem * servant,
CORBA_char * filename,
CORBA_Environment * ev);
static my_bool verbose,opt_compress;
static uint opt_mysql_port=0;
static my_string opt_mysql_unix_port=0;
static int first_error=0;
static MYSQL connection, *sock=0;
extern uint opt_mysql_port;
extern my_string opt_mysql_unix_port,host,user,password;
static struct format {
char *tablestart;
char *headerrowstart;
char *headercellstart;
char *headercellseparator;
char *headercellend;
char *headerrowend;
int headerformat; /* 0 - simple, 1 - left padded, 2 - right padded */
char *contentrowstart;
char *contentcellstart;
char *contentcellseparator;
char *contentcellend;
char *contentrowend;
int contentformat;
char *footerrowstart;
char *footercellstart;
char *footercellseparator;
char *footercellend;
char *footerrowend;
int footerformat;
char *tableend;
char *leftuppercorner;
char *rightuppercorner;
char *leftdowncorner;
char *rightdowncorner;
char *leftcross;
char *rightcross;
char *topcross;
char *middlecross;
char *bottomcross;
} Human, HTML, CSF, XML;

92
fs/mysqlcorbafs_test.c Normal file
View File

@ -0,0 +1,92 @@
#include <stdio.h>
#include <stdlib.h>
#include <orb/orbit.h>
#include "CorbaFS.h"
CorbaFS_FileSystem fs;
int
main (int argc, char *argv[])
{
CORBA_Environment ev;
CORBA_ORB orb;
CorbaFS_Inode inode;
CorbaFS_Buffer *buffer;
CorbaFS_DirEntSeq *dirents;
CorbaFS_dirent *dirent;
CORBA_unsigned_short mode;
CORBA_unsigned_long uid;
CORBA_unsigned_long gid;
CORBA_unsigned_long size;
CORBA_unsigned_long inodeNum;
CORBA_unsigned_short numLinks;
CORBA_long atime;
CORBA_long mtime;
CORBA_long ctime;
int i;
int niters = 10;
CORBA_exception_init(&ev);
orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
if(argc < 2)
{
printf("Need a binding ID thing as argv[1]\n");
return 1;
}
fs = CORBA_ORB_string_to_object(orb, argv[1], &ev);
if (!fs) {
printf("Cannot bind to %s\n", argv[1]);
return 1;
}
if (argc >= 3)
inode = CorbaFS_FileSystem_getInode(fs, argv[2], &ev);
else
inode = CorbaFS_FileSystem_getInode(fs, "/proc/cpuinfo", &ev);
if (!inode)
{
printf("Cannot get inode\n");
}
CorbaFS_Inode_getStatus(inode,
&mode,
&uid,
&gid,
&size,
&inodeNum,
&numLinks,
&atime,
&mtime,
&ctime,
&ev);
printf("inode = %x\n", inode);
CorbaFS_Inode_readpage(inode, &buffer, 100000, 100, &ev);
printf("readpage got %d bytes\n", buffer->_length);
printf("readpage returned : %s\n", buffer->_buffer);
if (argc >= 3)
dirents = CorbaFS_FileSystem_readdir(fs, argv[2], &ev);
else
dirents = CorbaFS_FileSystem_readdir(fs, "/", &ev);
dirent = dirents->_buffer;
for (i = 0; i < dirents->_length; i++)
{
printf("%d = %s\n", dirent->inode, dirent->name);
dirent++;
}
CORBA_Object_release(fs, &ev);
CORBA_Object_release((CORBA_Object)orb, &ev);
return 0;
}

11
fs/mysqlfsck Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
mountpoint=$*
if [#($mountpoint) -eq "0"];
then
exit;
fi

View File

@ -47,9 +47,10 @@ void ft_free_stopwords(void);
FT_DOCLIST * ft_init_search(void *, uint, byte *, uint, my_bool);
int ft_read_next(FT_DOCLIST *, char *);
#define ft_close_search(handler) my_free(((gptr)(handler)),MYF(0))
#define ft_get_relevance(handler) ((handler)->doc[(handler)->curdoc].weight)
#define ft_reinit_search(handler) (((FT_DOCLIST *)(handler))->curdoc=-1)
#define ft_close_search(handler) my_free(((gptr)(handler)),MYF(0))
#define ft_get_relevance(handler) ((handler)->doc[(handler)->curdoc].weight)
#define ft_get_docid(handler) ((handler)->doc[(handler)->curdoc].dpos)
#define ft_reinit_search(handler) (((FT_DOCLIST *)(handler))->curdoc=-1)
#ifdef __cplusplus
}

View File

@ -25,6 +25,10 @@
#define ETIME ETIMEDOUT /* For FreeBSD */
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__WIN__)
typedef CRITICAL_SECTION pthread_mutex_t;
@ -576,4 +580,8 @@ extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const));
#endif /* SAFE_STATISTICS */
#endif /* HAVE_ATOMIC_ADD */
#endif /* thread_safe_increment */
#ifdef __cplusplus
}
#endif
#endif /* _my_ptread_h */

View File

@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
@ -219,7 +219,7 @@ extern my_off_t mi_position(struct st_myisam_info *file);
extern int mi_status(struct st_myisam_info *info, MI_ISAMINFO *x, uint flag);
extern int mi_lock_database(struct st_myisam_info *file,int lock_type);
extern int mi_create(const char *name,uint keys,MI_KEYDEF *keydef,
uint columns, MI_COLUMNDEF *columndef,
uint columns, MI_COLUMNDEF *columndef,
uint uniques, MI_UNIQUEDEF *uniquedef,
MI_CREATE_INFO *create_info, uint flags);
extern int mi_delete_table(const char *name);
@ -295,17 +295,17 @@ typedef struct st_sort_info {
struct st_mi_check_param *param;
enum data_file_type new_data_file_type;
SORT_KEY_BLOCKS *key_block,*key_block_end;
uint key,find_length;
uint key,find_length,real_key_length;
my_off_t pos,max_pos,filepos,start_recpos,filelength,dupp,buff_length;
ha_rows max_records;
ulonglong unique[MI_MAX_KEY_SEG+1];
my_bool fix_datafile;
char *record,*buff;
void *wordlist, *wordptr;
MI_KEYDEF *keyinfo;
MI_KEYSEG *keyseg;
} SORT_INFO;
typedef struct st_mi_check_param
{
ulonglong auto_increment_value;

View File

@ -165,7 +165,7 @@ int my_net_write(NET *net,const char *packet,unsigned long len);
int net_write_command(NET *net,unsigned char command,const char *packet,
unsigned long len);
int net_real_write(NET *net,const char *packet,unsigned long len);
unsigned int my_net_read(NET *net);
unsigned long my_net_read(NET *net);
struct rand_struct {
unsigned long seed1,seed2,max_value;

View File

@ -52,6 +52,10 @@ Vio* vio_new_win32pipe(HANDLE hPipe);
#endif
void vio_delete(Vio* vio);
#ifdef EMBEDDED_LIBRARY
void vio_reset(Vio *vio);
#endif
/*
* vio_read and vio_write should have the same semantics
* as read(2) and write(2).

View File

@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
@ -22,6 +22,11 @@
** 3 byte length & 1 byte package-number.
*/
#ifdef EMBEDDED_LIBRARY
#define net_read_timeout net_read_timeout1
#define net_write_timeout net_write_timeout1
#endif
#ifdef __WIN__
#include <winsock.h>
#endif
@ -35,13 +40,21 @@
#include <errno.h>
#include <sys/types.h>
#include <violite.h>
#include <assert.h>
#ifdef MYSQL_SERVER
ulong max_allowed_packet=65536;
extern ulong net_read_timeout,net_write_timeout;
extern uint test_flags;
#else
ulong max_allowed_packet=16*1024*1024L;
/*
** Give error if a too big packet is found
** The server can change this with the -O switch, but because the client
** can't normally do this the client should have a bigger max_allowed_packet.
*/
ulong max_allowed_packet=~0L;
ulong net_read_timeout= NET_READ_TIMEOUT;
ulong net_write_timeout= NET_WRITE_TIMEOUT;
#endif
@ -74,7 +87,7 @@ typedef my_bool ALARM;
#define thr_alarm_in_use(A) (*(A))
#define thr_end_alarm(A)
#define thr_alarm(A,B,C) local_thr_alarm((A),(B),(C))
static inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
{
*A=1;
return 0;
@ -84,28 +97,25 @@ static inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM
#endif
#ifdef MYSQL_SERVER
extern ulong bytes_sent, bytes_received;
extern ulong bytes_sent, bytes_received;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
#else
#undef statistic_add
#define statistic_add(A,B,C)
#endif
/*
** Give error if a too big packet is found
** The server can change this with the -O switch, but because the client
** can't normally do this the client should have a bigger max-buffer.
*/
#define TEST_BLOCKING 8
static int net_write_buff(NET *net,const char *packet,uint len);
static int net_write_buff(NET *net,const char *packet,ulong len);
#define MAX_THREE_BYTES 255L*255L*255L
/* Init with packet info */
int my_net_init(NET *net, Vio* vio)
{
if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME))))
if (!(net->buff=(uchar*) my_malloc(net_buffer_length+
NET_HEADER_SIZE + COMP_HEADER_SIZE,
MYF(MY_WME))))
return 1;
if (net_buffer_length > max_allowed_packet)
max_allowed_packet=net_buffer_length;
@ -152,8 +162,12 @@ static my_bool net_realloc(NET *net, ulong length)
net->last_errno=ER_NET_PACKET_TOO_LARGE;
return 1;
}
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
/* We must allocate some extra bytes for the end 0 and to be able to
read big compressed blocks */
if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length +
NET_HEADER_SIZE + COMP_HEADER_SIZE,
MYF(MY_WME))))
{
net->error=1;
#ifdef MYSQL_SERVER
@ -209,18 +223,34 @@ int net_flush(NET *net)
** Write something to server/client buffer
*****************************************************************************/
/*
** Write a logical packet with packet header
** Format: Packet length (3 bytes), packet number(1 byte)
** When compression is used a 3 byte compression length is added
** NOTE: If compression is used the original package is destroyed!
** NOTE: If compression is used the original package is modified!
*/
int
my_net_write(NET *net,const char *packet,ulong len)
{
uchar buff[NET_HEADER_SIZE];
/*
Big packets are handled by splitting them in packets of MAX_THREE_BYTES
length. The last packet is always a packet that is < MAX_THREE_BYTES.
(The last packet may even have a lengt of 0)
*/
while (len >= MAX_THREE_BYTES)
{
const ulong z_size = MAX_THREE_BYTES;
int3store(buff, z_size);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
if (net_write_buff(net, (char*) buff, NET_HEADER_SIZE) ||
net_write_buff(net, packet, z_size))
return 1;
packet += z_size;
len-= z_size;
}
/* Write last packet */
int3store(buff,len);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
@ -228,23 +258,54 @@ my_net_write(NET *net,const char *packet,ulong len)
return net_write_buff(net,packet,len);
}
/*
Send a command to the server.
As the command is part of the first data packet, we have to do some data
juggling to put the command in there, without having to create a new
packet.
This function will split big packets into sub-packets if needed.
(Each sub packet can only be 2^24 bytes)
*/
int
net_write_command(NET *net,uchar command,const char *packet,ulong len)
{
uchar buff[NET_HEADER_SIZE+1];
uint length=len+1; /* 1 extra byte for command */
uchar buff[NET_HEADER_SIZE+1];
uint header_size=NET_HEADER_SIZE+1;
buff[4]=command; /* For first packet */
if (length >= MAX_THREE_BYTES)
{
/* Take into account that we have the command in the first header */
len= MAX_THREE_BYTES -1;
do
{
int3store(buff, MAX_THREE_BYTES);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
if (net_write_buff(net,(char*) buff, header_size) ||
net_write_buff(net,packet,len))
return 1;
packet+= len;
length-= MAX_THREE_BYTES;
len=MAX_THREE_BYTES;
header_size=NET_HEADER_SIZE;
} while (length >= MAX_THREE_BYTES);
len=length; /* Data left to be written */
}
int3store(buff,length);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
buff[4]=command;
if (net_write_buff(net,(char*) buff,5))
return 1;
return test(net_write_buff(net,packet,len) || net_flush(net));
return test(net_write_buff(net,(char*) buff,header_size) ||
net_write_buff(net,packet,len) || net_flush(net));
}
/*
Caching the data in a local buffer before sending it.
One can force the buffer to be flushed with 'net_flush'.
*/
static int
net_write_buff(NET *net,const char *packet,uint len)
net_write_buff(NET *net,const char *packet,ulong len)
{
uint left_length=(uint) (net->buff_end - net->write_pos);
@ -263,7 +324,11 @@ net_write_buff(NET *net,const char *packet,uint len)
return 0;
}
/* Read and write using timeouts */
/*
Read and write one packet using timeouts.
If needed, the packet is compressed before sending.
*/
int
net_real_write(NET *net,const char *packet,ulong len)
@ -271,7 +336,7 @@ net_real_write(NET *net,const char *packet,ulong len)
int length;
char *pos,*end;
thr_alarm_t alarmed;
#if !defined(__WIN__) && !defined(__EMX__)
#if !defined(__WIN__)
ALARM alarm_buff;
#endif
uint retry_count=0;
@ -427,19 +492,25 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
{
my_bool interrupted = vio_should_retry(net->vio);
if (!thr_got_alarm(&alarmed) && interrupted)
{ /* Probably in MIT threads */
{ /* Probably in MIT threads */
if (retry_count++ < RETRY_COUNT)
continue;
}
return;
}
remain -=(ulong) length;
statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
remain -= length;
statistic_add(bytes_received,length,&LOCK_bytes_received);
}
}
#endif /* MYSQL_SERVER */
/*
Reads one packet to net->buff + net->where_b
Returns length of packet. Long packets are handled by my_net_read().
This function reallocates the net->buff buffer if necessary.
*/
static uint
my_real_read(NET *net, ulong *complen)
{
@ -576,12 +647,13 @@ my_real_read(NET *net, ulong *complen)
#endif
len=uint3korr(net->buff+net->where_b);
if (!len) /* End of big multi-packet */
goto end;
helping = max(len,*complen) + net->where_b;
/* The necessary size of net->buff */
if (helping >= net->max_packet)
{
/* We must allocate one extra byte for the end null */
if (net_realloc(net,helping+1))
if (net_realloc(net,helping))
{
#ifdef MYSQL_SERVER
if (i == 1)
@ -606,7 +678,21 @@ end:
return(len);
}
uint
/*
Read a packet from the client/server and return it without the internal
package header.
If the packet is the first packet of a multi-packet packet
(which is indicated by the length of the packet = 0xffffff) then
all sub packets are read and concatenated.
If the packet was compressed, its uncompressed and the length of the
uncompressed packet is returned.
The function returns the length of the found packet or packet_error.
net->read_pos points to the read data.
*/
ulong
my_net_read(NET *net)
{
ulong len,complen;
@ -615,65 +701,126 @@ my_net_read(NET *net)
if (!net->compress)
{
#endif
len = my_real_read (net,&complen);
len = my_real_read(net,&complen);
if (len == MAX_THREE_BYTES)
{
/* First packet of a multi-packet. Concatenate the packets */
int save_pos = net->where_b;
ulong total_length=0;
do
{
net->where_b += len;
total_length += len;
len = my_real_read (net,&complen);
} while (len == MAX_THREE_BYTES);
if (len != packet_error)
len+= total_length;
net->where_b = save_pos;
}
net->read_pos = net->buff + net->where_b;
if (len != packet_error)
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
return len;
#ifdef HAVE_COMPRESS
}
if (net->remain_in_buf)
net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
for (;;)
else
{
/* We are using the compressed protocol */
ulong buf_length= net->buf_length;
ulong start_of_packet= net->buf_length - net->remain_in_buf;
ulong first_packet_offset=start_of_packet;
uint read_length, multi_byte_packet=0;
if (net->remain_in_buf)
{
uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
if (net->remain_in_buf >= 4)
{
net->length = uint3korr(pos);
if (net->length <= net->remain_in_buf - 4)
{
/* We have a full packet */
len=net->length;
net->remain_in_buf -= net->length + 4;
net->read_pos=pos + 4;
break; /* We have a full packet */
}
}
/* Move data down to read next data packet after current one */
if (net->buf_length != net->remain_in_buf)
{
memmove(net->buff,pos,net->remain_in_buf);
net->buf_length=net->remain_in_buf;
}
net->where_b=net->buf_length;
/* Restore the character that was overwritten by the end 0 */
net->buff[start_of_packet]=net->save_char;
}
else
{
net->where_b=0;
net->buf_length=0;
/* reuse buffer, as there is noting in it that we need */
buf_length=start_of_packet=first_packet_offset=0;
}
for (;;)
{
ulong packet_len;
if (buf_length - start_of_packet >= NET_HEADER_SIZE)
{
read_length = uint3korr(net->buff+start_of_packet);
if (!read_length)
{
/* End of multi-byte packet */
start_of_packet += NET_HEADER_SIZE;
break;
}
if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
{
if (multi_byte_packet)
{
/* Remove packet header for second packet */
memmove(net->buff + first_packet_offset + start_of_packet,
net->buff + first_packet_offset + start_of_packet +
NET_HEADER_SIZE,
buf_length - start_of_packet);
start_of_packet += read_length;
buf_length -= NET_HEADER_SIZE;
}
else
start_of_packet+= read_length + NET_HEADER_SIZE;
if (read_length != MAX_THREE_BYTES) /* last package */
{
multi_byte_packet= 0; // No last zero length packet
break;
}
multi_byte_packet= NET_HEADER_SIZE;
/* Move data down to read next data packet after current one */
if (first_packet_offset)
{
memmove(net->buff,net->buff+first_packet_offset,
buf_length-first_packet_offset);
buf_length-=first_packet_offset;
start_of_packet -= first_packet_offset;
first_packet_offset=0;
}
continue;
}
}
/* Move data down to read next data packet after current one */
if (first_packet_offset)
{
memmove(net->buff,net->buff+first_packet_offset,
buf_length-first_packet_offset);
buf_length-=first_packet_offset;
start_of_packet -= first_packet_offset;
first_packet_offset=0;
}
net->where_b=buf_length;
if ((packet_len = my_real_read(net,&complen)) == packet_error)
return packet_error;
if (my_uncompress((byte*) net->buff + net->where_b, &packet_len,
&complen))
{
net->error=2; /* caller will close socket */
#ifdef MYSQL_SERVER
net->last_errno=ER_NET_UNCOMPRESS_ERROR;
#endif
return packet_error;
}
buf_length+=packet_len;
}
if ((len = my_real_read(net,&complen)) == packet_error)
break;
if (my_uncompress((byte*) net->buff + net->where_b, &len, &complen))
{
len= packet_error;
net->error=2; /* caller will close socket */
#ifdef MYSQL_SERVER
net->last_errno=ER_NET_UNCOMPRESS_ERROR;
#endif
break;
}
net->buf_length+=len;
net->remain_in_buf+=len;
}
if (len != packet_error)
{
net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;
net->buf_length= buf_length;
net->remain_in_buf= buf_length - start_of_packet;
len = ((uint) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
multi_byte_packet);
net->save_char= net->read_pos[len]; /* Must be saved */
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
}
#endif /* HAVE_COMPRESS */
return len;
#endif
}

106
libmysqld/Makefile.am Normal file
View File

@ -0,0 +1,106 @@
# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the Free
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
# MA 02111-1307, USA
#
# This file is public domain and comes with NO WARRANTY of any kind
MYSQLDATAdir = $(localstatedir)
MYSQLSHAREdir = $(pkgdatadir)
MYSQLBASEdir= $(prefix)
DEFS = -DEMBEDDED_LIBRARY -DMYSQL_SERVER \
-DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
-DDATADIR="\"$(MYSQLDATAdir)\"" \
-DSHAREDIR="\"$(MYSQLSHAREdir)\""
INCLUDES = @MT_INCLUDES@ @bdb_includes@ -I$(srcdir)/../include -I../include \
-I$(srcdir)/.. -I$(top_srcdir) -I.. -I../sql -I../regex
## XXX: should we use client or server LDFLAGS for libmysqld?
LDADD = @CLIENT_EXTRA_LDFLAGS@ libmysqld.la
pkglib_LTLIBRARIES = libmysqld.la
libmysqld_la_SOURCES = libmysqld.c lib_sql.cc
libmysqlsources = errmsg.c get_password.c password.c
## XXX: we should not have to duplicate info from the sources list
libmysqlobjects = errmsg.lo get_password.lo password.lo
sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \
ha_berkeley.cc ha_heap.cc ha_isam.cc ha_isammrg.cc \
ha_myisam.cc ha_myisammrg.cc handler.cc hostname.cc init.cc \
item.cc item_buff.cc item_cmpfunc.cc item_create.cc \
item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \
item_uniq.cc key.cc lock.cc log.cc log_event.cc md5.c \
mini_client.cc net_pkg.cc net_serv.cc opt_ft.cc opt_range.cc \
opt_sum.cc procedure.cc records.cc slave.cc sql_acl.cc \
sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \
sql_crypt.cc sql_db.cc sql_delete.cc sql_insert.cc sql_lex.cc \
sql_list.cc sql_load.cc sql_manager.cc sql_map.cc sql_parse.cc \
sql_rename.cc sql_repl.cc sql_select.cc sql_show.cc \
sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \
sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \
unireg.cc
## XXX: we should not have to duplicate info from the sources list
sqlobjects = convert.lo derror.lo field.lo field_conv.lo filesort.lo \
ha_berkeley.lo ha_heap.lo ha_isam.lo ha_isammrg.lo \
ha_myisam.lo ha_myisammrg.lo handler.lo hostname.lo init.lo \
item.lo item_buff.lo item_cmpfunc.lo item_create.lo \
item_func.lo item_strfunc.lo item_sum.lo item_timefunc.lo \
item_uniq.lo key.lo lock.lo log.lo log_event.lo md5.lo \
mini_client.lo net_pkg.lo net_serv.lo opt_ft.lo opt_range.lo \
opt_sum.lo procedure.lo records.lo slave.lo sql_acl.lo \
sql_analyse.lo sql_base.lo sql_cache.lo sql_class.lo \
sql_crypt.lo sql_db.lo sql_delete.lo sql_insert.lo sql_lex.lo \
sql_list.lo sql_load.lo sql_manager.lo sql_map.lo sql_parse.lo \
sql_rename.lo sql_repl.lo sql_select.lo sql_show.lo \
sql_string.lo sql_table.lo sql_test.lo sql_udf.lo \
sql_update.lo sql_yacc.lo table.lo thr_malloc.lo time.lo \
unireg.lo
EXTRA_DIST = lib_vio.c
# automake misses these
sql_yacc.cc sql_yacc.h: $(top_srcdir)/sql/sql_yacc.yy
libmysqld_la_LIBADD = $(sqlobjects) $(libmysqlobjects)
## XXX: any time the client interface changes, we'll need to bump
## the version info for libmysqld; however, it's possible for the
## libmysqld interface to change without affecting the standard
## libmysqlclient interface. Should we make a separate version
## string for the two?
libmysqld_la_LDFLAGS = -version-info @SHARED_LIB_VERSION@
CLEANFILES = $(libmysqld_la_LIBADD) libmysqld.la
# This is called from the toplevel makefile
link_sources:
set -x; \
for f in $(sqlsources); do \
rm -f $(srcdir)/$$f; \
@LN_CP_F@ $(srcdir)/../sql/$$f $(srcdir)/$$f; \
done; \
for f in $(libmysqlsources); do \
rm -f $(srcdir)/$$f; \
@LN_CP_F@ $(srcdir)/../libmysql/$$f $(srcdir)/$$f; \
done
clean-local:
rm -f `echo $(sqlsources) $(libmysqlsources) | sed "s;\.lo;.c;g"` \
$(top_srcdir)/linked_libmysqld_sources
# Don't update the files from bitkeeper
%::SCCS/s.%

26
libmysqld/README Normal file
View File

@ -0,0 +1,26 @@
LIBRARY (ONE_PROCESS VERSION) OF MYSQL CLIENT
Installation steps:
1) unpack mysql-3.23.27-beta.tar tarball source version (get from www.mysql.com.sg)
2) patch mysql-3.23.27-beta with lbver-3.23.27-beta.diff:
patch -p0 <lbver-3.23.27-beta.diff
3) cd mysql-3.23.27-beta
4) autoconf
7) ./configure --prefix=/usr/local/mysql --with-library-version
8) make
9) make install (should have the root privileges)
10)mkdir /usr/local/mysql/var (if not already)
15) cd ../client
19) ./mysql (start libarary version mysql)
mysql> create database db1;
mysql> use db1;
mysql> create table a123(i integer)
...... now you can work with library version....

16
libmysqld/WHITEPAPER Normal file
View File

@ -0,0 +1,16 @@
LIBRARY VERSION DESIGN (EMBEDDED SERVER)
- The library version of MySQL server is the client library that contains embedded server.
- This client DLL has name : libmysqlclient_e (.la)
- The client application that supposed to use MySQL LV need to be rebuilt against libmysqlclient_e.la. The rebuild process is necessary, because libmysqlclient_e is a LIBTOOL object, which has the different LIBS list compared to the original libmysqlclient.la.
- The client and the server code run in the same process and the same thread;
- The server code is invoked when client writes the command to the net, and when connection is established;

14
libmysqld/copyright Normal file
View File

@ -0,0 +1,14 @@
/*
* Copyright (c) 2000
* SWsoft company
*
* This material is provided "as is", with absolutely no warranty expressed
* or implied. Any use is at your own risk.
*
* Permission to use or copy this software for any purpose is hereby granted
* without fee, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*
*/

41
libmysqld/lib_load.cc Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2000
* SWsoft company
*
* This material is provided "as is", with absolutely no warranty expressed
* or implied. Any use is at your own risk.
*
* Permission to use or copy this software for any purpose is hereby granted
* without fee, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*
*/
/* Copy data from a textfile to table */
#include "mysql_priv.h"
#include <my_dir.h>
#include <m_ctype.h>
int
mysql_load_internal(THD * thd, sql_exchange * ex, TABLE_LIST * table_list,
List<Item> & fields, enum enum_duplicates handle_duplicates,
bool read_file_from_client, thr_lock_type lock_type);
int
mysql_load(THD * thd, sql_exchange * ex, TABLE_LIST * table_list,
List<Item> & fields, enum enum_duplicates handle_duplicates,
bool read_file_from_client, thr_lock_type lock_type)
{
printf("SWSOFT_MYSQL load: \n");
read_file_from_client = 0; //server is always in the same process
return mysql_load_internal(thd, ex, table_list, fields, handle_duplicates,
read_file_from_client, lock_type);
}
#define mysql_load mysql_load_internal
#include "../sql/sql_load.cc"

650
libmysqld/lib_sql.cc Normal file
View File

@ -0,0 +1,650 @@
/*
* Copyright (c) 2000
* SWsoft company
*
* This material is provided "as is", with absolutely no warranty expressed
* or implied. Any use is at your own risk.
*
* Permission to use or copy this software for any purpose is hereby granted
* without fee, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*
*/
#include "global.h"
#include "my_pthread.h"
#include "sys/types.h"
#include "../regex/regex.h"
#include "my_sys.h"
#define main main1
#define mysql_unix_port mysql_inix_port1
#define mysql_port mysql_port1
#define net_read_timeout net_read_timeout1
#define net_write_timeout net_write_timeout1
#define changeable_vars changeable_vars1
//#define mysql_tmpdir mysql_tmpdir1
extern "C"
{
#include "mysql_com.h"
}
class THD;
static int
check_connections1(THD * thd);
static bool
check_user(THD *thd, enum_server_command command,const char *user, const char *passwd, const char *db, bool check_count);
static int
check_connections2(THD * thd);
extern void free_defaults(char ** argv);
void free_defaults_internal(char ** argv){if (argv) free_defaults(argv);}
#define free_defaults free_defaults_internal
char mysql_data_home[FN_REFLEN];
char * get_mysql_data_home(){return mysql_data_home;};
#define mysql_data_home mysql_data_home_internal
#include "../sql/mysqld.cc"
#include "lib_vio.c"
#define SCRAMBLE_LENGTH 8
extern "C" {
/*
void
free_defaults(char ** argv) {};
void
load_defaults(const char *, const char **, int *, char ***) {};
*/
char *
get_mysql_home(){ return mysql_home;};
char *
get_mysql_real_data_home(){ return mysql_real_data_home;};
bool lib_dispatch_command(enum enum_server_command command, NET *net,
const char *arg, ulong length)
{
net_new_transaction(&((THD *)net->vio->dest_thd)->net);
return dispatch_command(command, (THD *)net->vio->dest_thd, (char *)arg, length + 1);
}
void
lib_connection_phase(NET * net, int phase)
{
THD * thd;
thd = (THD *)(net->vio->dest_thd);
if (thd)
{
switch (phase)
{
case 2:
check_connections2(thd);
break;
}
}
}
}
void start_embedded_conn1(NET * net)
{
THD * thd = new THD;
my_net_init(&thd->net,NULL);
/* if (protocol_version>9) */
thd->net.return_errno=1;
thd->thread_id = thread_id++;
Vio * v = net->vio;
if (!v)
{
v = vio_new(0,VIO_CLOSED,0);
net->vio = v;
}
if (v)
{
v -> dest_thd = thd;
/* v -> dest_net = &thd->net; XXX: Probably not needed? */
}
thd->net.vio = v;
if (thd->store_globals())
{
printf("store_globals failed.\n");
return;
}
thd->mysys_var=my_thread_var;
thd->dbug_thread_id=my_thread_id();
thd->thread_stack= (char*) &thd;
if (thd->max_join_size == HA_POS_ERROR)
thd->options |= OPTION_BIG_SELECTS;
if (thd->client_capabilities & CLIENT_COMPRESS)
net->compress=1; // Use compression
if (thd->options & OPTION_ANSI_MODE)
thd->client_capabilities|=CLIENT_IGNORE_SPACE;
thd->proc_info=0; // Remove 'login'
thd->command=COM_SLEEP;
thd->version=refresh_version;
thd->set_time();
init_sql_alloc(&thd->mem_root,8192,8192);
check_connections1(thd);
}
static int
check_connections1(THD *thd)
{
uint connect_errors=0;
NET *net= &thd->net;
/*
** store the connection details
*/
DBUG_PRINT("info", (("check_connections called by thread %d"),
thd->thread_id));
DBUG_PRINT("general",("New connection received on %s",
vio_description(net->vio)));
if (!thd->host) // If TCP/IP connection
{
thd->host=(char*) localhost;
}
else /* Hostname given means that the connection was on a socket */
{
DBUG_PRINT("general",("Host: %s",thd->host));
thd->ip=0;
bzero((char*) &thd->remote,sizeof(struct sockaddr));
}
//vio_keepalive(net->vio, TRUE);
/* nasty, but any other way? */
uint pkt_len = 0;
char buff[80],*end;
int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
CLIENT_TRANSACTIONS;
LINT_INIT(pkt_len);
end=strmov(buff,server_version)+1;
int4store((uchar*) end,thd->thread_id);
end+=4;
memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
end+=SCRAMBLE_LENGTH +1;
#ifdef HAVE_COMPRESS
client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
int2store(end,client_flags);
end[2]=MY_CHARSET_CURRENT;
#define MIN_HANDSHAKE_SIZE 6
int2store(end+3,thd->server_status);
bzero(end+5,13);
end+=18;
if (net_write_command(net,protocol_version, buff,
(uint) (end-buff)))
{
inc_host_errors(&thd->remote.sin_addr);
return(ER_HANDSHAKE_ERROR);
}
return 0;
}
static int
check_connections2(THD * thd)
{
uint connect_errors=0;
uint pkt_len = 0;
NET * net = &thd -> net;
if (protocol_version>9) net -> return_errno=1;
if ( (pkt_len=my_net_read(net)) == packet_error ||
pkt_len < MIN_HANDSHAKE_SIZE)
{
inc_host_errors(&thd->remote.sin_addr);
return(ER_HANDSHAKE_ERROR);
}
#ifdef _CUSTOMCONFIG_
#include "_cust_sql_parse.h"
#endif
if (connect_errors)
reset_host_errors(&thd->remote.sin_addr);
if (thd->packet.alloc(net_buffer_length))
return(ER_OUT_OF_RESOURCES);
thd->client_capabilities=uint2korr(net->read_pos);
thd->max_packet_length=uint3korr(net->read_pos+2);
char *user= (char*) net->read_pos+5;
char *passwd= strend(user)+1;
char *db=0;
if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH)
return ER_HANDSHAKE_ERROR;
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
db=strend(passwd)+1;
if (thd->client_capabilities & CLIENT_INTERACTIVE)
thd->inactive_timeout=net_interactive_timeout;
if (thd->client_capabilities & CLIENT_TRANSACTIONS)
thd->net.return_status= &thd->server_status;
net->timeout=net_read_timeout;
if (check_user(thd,COM_CONNECT, user, passwd, db, 1))
return (-1);
thd->password=test(passwd[0]);
return 0;
}
static bool check_user(THD *thd,enum_server_command command, const char *user,
const char *passwd, const char *db, bool check_count)
{
NET *net= &thd->net;
thd->db=0;
if (!(thd->user = my_strdup(user, MYF(0))))
{
send_error(net,ER_OUT_OF_RESOURCES);
return 1;
}
thd->master_access=acl_getroot(thd->host, thd->ip, thd->user,
passwd, thd->scramble, &thd->priv_user,
protocol_version == 9 ||
!(thd->client_capabilities &
CLIENT_LONG_PASSWORD));
DBUG_PRINT("general",
("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
thd->client_capabilities, thd->max_packet_length,
thd->host ? thd->host : thd->ip, thd->priv_user,
passwd[0] ? "yes": "no",
thd->master_access, thd->db ? thd->db : "*none*"));
if (thd->master_access & NO_ACCESS)
{
net_printf(net, ER_ACCESS_DENIED_ERROR,
thd->user,
thd->host ? thd->host : thd->ip,
passwd[0] ? ER(ER_YES) : ER(ER_NO));
mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
thd->user,
thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
passwd[0] ? ER(ER_YES) : ER(ER_NO));
return(1); // Error already given
}
if (check_count)
{
VOID(pthread_mutex_lock(&LOCK_thread_count));
bool tmp=(thread_count - delayed_insert_threads >= max_connections &&
!(thd->master_access & PROCESS_ACL));
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (tmp)
{ // Too many connections
send_error(net, ER_CON_COUNT_ERROR);
return(1);
}
}
mysql_log.write(thd,command,
(thd->priv_user == thd->user ?
(char*) "%s@%s on %s" :
(char*) "%s@%s as anonymous on %s"),
user,
thd->host ? thd->host : thd->ip ? thd->ip : "unknown ip",
db ? db : (char*) "");
thd->db_access=0;
if (db && db[0])
return test(mysql_change_db(thd,db));
else
send_ok(net); // Ready to handle questions
return 0; // ok
}
extern "C"{
void start_embedded_connection(NET * net)
{
start_embedded_conn1(net);
}
//====================================================================
void embedded_srv_init(void)
{
DEBUGGER_OFF;
char hostname[FN_REFLEN];
my_umask=0660; // Default umask for new files
my_umask_dir=0700; // Default umask for new directories
MY_INIT((char *)"mysqld"); // init my_sys library & pthreads
tzset(); // Set tzname
start_time=time((time_t*) 0);
#ifdef HAVE_TZNAME
#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
{
struct tm tm_tmp;
localtime_r(&start_time,&tm_tmp);
strmov(time_zone,tzname[tm_tmp.tm_isdst == 1 ? 1 : 0]);
}
#else
{
struct tm *start_tm;
start_tm=localtime(&start_time);
strmov(time_zone=tzname[start_tm->tm_isdst == 1 ? 1 : 0]);
}
#endif
#endif
if (gethostname(hostname,sizeof(hostname)-4) < 0)
strmov(hostname,"mysql");
strmov(pidfile_name,hostname);
strmov(strcend(pidfile_name,'.'),".pid"); // Add extension
#ifdef DEMO_VERSION
strcat(server_version,"-demo");
#endif
#ifdef SHAREWARE_VERSION
strcat(server_version,"-shareware");
#endif
#ifndef DBUG_OFF
strcat(server_version,"-debug");
#endif
strcat(server_version,"-library-ver");
#ifdef _CUSTOMSTARTUPCONFIG_
if (_cust_check_startup())
{
/* _cust_check_startup will report startup failure error */
exit( 1 );
}
#endif
// load_defaults("my",load_default_groups,&d_argc, (char***)&d_argv);
defaults_argv=0;
mysql_tmpdir=getenv("TMPDIR"); /* Use this if possible */
#ifdef __WIN__
if (!mysql_tmpdir)
mysql_tmpdir=getenv("TEMP");
if (!mysql_tmpdir)
mysql_tmpdir=getenv("TMP");
#endif
if (!mysql_tmpdir || !mysql_tmpdir[0])
mysql_tmpdir=strdup((char*) P_tmpdir);
set_options();
fix_paths();
if (opt_log || opt_update_log || opt_slow_log || opt_bin_log)
strcat(server_version,"-log");
DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname,
server_version, SYSTEM_TYPE,MACHINE_TYPE));
/* These must be set early */
(void) pthread_cond_init(&COND_thread_count,NULL);
(void) pthread_mutex_init(&LOCK_mysql_create_db,NULL);
(void) pthread_mutex_init(&LOCK_Acl,NULL);
(void) pthread_mutex_init(&LOCK_grant,NULL);
(void) pthread_mutex_init(&LOCK_open,NULL);
(void) pthread_mutex_init(&LOCK_thread_count,NULL);
(void) pthread_mutex_init(&LOCK_mapped_file,NULL);
(void) pthread_mutex_init(&LOCK_status,NULL);
(void) pthread_mutex_init(&LOCK_error_log,NULL);
(void) pthread_mutex_init(&LOCK_delayed_insert,NULL);
(void) pthread_mutex_init(&LOCK_delayed_status,NULL);
(void) pthread_mutex_init(&LOCK_delayed_create,NULL);
(void) pthread_cond_init(&COND_refresh,NULL);
(void) pthread_cond_init(&COND_thread_cache,NULL);
(void) pthread_cond_init(&COND_flush_thread_cache,NULL);
(void) pthread_cond_init(&COND_manager,NULL);
(void) pthread_mutex_init(&LOCK_manager,NULL);
(void) pthread_mutex_init(&LOCK_crypt,NULL);
(void) pthread_mutex_init(&LOCK_bytes_sent,NULL);
(void) pthread_mutex_init(&LOCK_bytes_received,NULL);
(void) pthread_mutex_init(&LOCK_timezone,NULL);
(void) pthread_mutex_init(&LOCK_binlog_update, NULL);
(void) pthread_mutex_init(&LOCK_slave, NULL);
(void) pthread_mutex_init(&LOCK_server_id, NULL);
(void) pthread_cond_init(&COND_binlog_update, NULL);
(void) pthread_cond_init(&COND_slave_stopped, NULL);
if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
unireg_abort(1);
charsets_list = list_charsets(MYF(MY_COMPILED_SETS|MY_CONFIG_SETS));
if (!(opt_specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),CONNECT_PRIOR);
/* Parameter for threads created for connections */
(void) pthread_attr_init(&connection_attrib);
(void) pthread_attr_setdetachstate(&connection_attrib,
PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&connection_attrib,thread_stack);
if (!(opt_specialflag & SPECIAL_NO_PRIOR))
my_pthread_attr_setprio(&connection_attrib,WAIT_PRIOR);
pthread_attr_setscope(&connection_attrib, PTHREAD_SCOPE_SYSTEM);
#ifdef SET_RLIMIT_NOFILE
/* connections and databases neads lots of files */
{
uint wanted_files=10+(uint) max(max_connections*5,
max_connections+table_cache_size*2);
uint files=set_maximum_open_files(wanted_files);
if (files && files < wanted_files) // Some systems return 0
{
max_connections= (ulong) min((files-10),max_connections);
table_cache_size= (ulong) max((files-10-max_connections)/2,64);
DBUG_PRINT("warning",
("Changed limits: max_connections: %ld table_cache: %ld",
max_connections,table_cache_size));
sql_print_error("Warning: Changed limits: max_connections: %ld table_cache: %ld",max_connections,table_cache_size);
}
}
#endif
unireg_init(opt_specialflag); /* Set up extern variabels */
init_errmessage(); /* Read error messages from file */
lex_init();
item_init();
mysys_uses_curses=0;
#ifdef USE_REGEX
regex_init();
#endif
select_thread=pthread_self();
select_thread_in_use=1;
/*
** We have enough space for fiddling with the argv, continue
*/
umask(((~my_umask) & 0666));
// strcpy(mysql_real_data_home, "/usr/local");
//if (my_setwd(mysql_real_data_home,MYF(MY_WME)))
//{
// unireg_abort(1); /* purecov: inspected */
//}
//mysql_data_home[0]=FN_CURLIB; // all paths are relative from here
//mysql_data_home[1]=0;
strcpy(get_mysql_data_home(), mysql_real_data_home);
//server_init();
table_cache_init();
hostname_cache_init();
sql_cache_init();
randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
reset_floating_point_exceptions();
init_thr_lock();
/* Setup log files */
if (opt_log)
open_log(&mysql_log, hostname, opt_logname, ".log", LOG_NORMAL);
if (opt_update_log)
open_log(&mysql_update_log, hostname, opt_update_logname, "",
LOG_NEW);
if (opt_bin_log)
{
if(server_id)
{
if (!opt_bin_logname)
{
char tmp[FN_REFLEN];
strnmov(tmp,hostname,FN_REFLEN-5);
strmov(strcend(tmp,'.'),"-bin");
opt_bin_logname=my_strdup(tmp,MYF(MY_WME));
}
mysql_bin_log.set_index_file_name(opt_binlog_index_name);
open_log(&mysql_bin_log, hostname, opt_bin_logname, "-bin",
LOG_BIN);
}
else
sql_print_error("Server id is not set - binary logging disabled");
}
if (opt_slow_log)
open_log(&mysql_slow_log, hostname, opt_slow_logname, "-slow.log",
LOG_NORMAL);
if (ha_init())
{
sql_print_error("Can't init databases");
exit(1);
}
#ifdef HAVE_MLOCKALL
if (locked_in_memory && !geteuid())
{
ha_key_cache();
if (mlockall(MCL_CURRENT))
{
sql_print_error("Warning: Failed to lock memory. Errno: %d\n",errno);
}
else
locked_in_memory=1;
}
#else
locked_in_memory=0;
#endif
if (opt_myisam_log)
(void) mi_log( 1 );
ft_init_stopwords(ft_precompiled_stopwords); /* SerG */
/*
init signals & alarm
After this we can't quit by a simple unireg_abort
*/
error_handler_hook = my_message_sql;
if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_NET,NULL) ||
pthread_key_create(&THR_MALLOC,NULL))
{
sql_print_error("Can't create thread-keys");
exit(1);
}
// init_signals(); // Creates pidfile
//SWSOFT+
opt_noacl = 1;
if (acl_init(opt_noacl))
{
select_thread_in_use=0;
(void) pthread_kill(signal_thread,MYSQL_KILL_SIGNAL);
exit(1);
}
if (!opt_noacl)
(void) grant_init();
#ifdef HAVE_DLOPEN
if (!opt_noacl)
udf_init();
#endif
if (opt_bootstrap)
{
int error=bootstrap(stdin);
end_thr_alarm(); // Don't allow alarms
unireg_abort(error ? 1 : 0);
}
if (opt_init_file)
{
if (read_init_file(opt_init_file))
{
end_thr_alarm(); // Don't allow alarms
unireg_abort(1);
}
}
(void) thr_setconcurrency(concurrency); // 10 by default
if (flush_time && flush_time != ~(ulong) 0L)
{
pthread_t hThread;
if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
sql_print_error("Warning: Can't create thread to manage maintenance");
}
// slave thread
if(master_host)
{
if(server_id)
{
pthread_t hThread;
if(!opt_skip_slave_start &&
pthread_create(&hThread, &connection_attrib, handle_slave, 0))
sql_print_error("Warning: Can't create thread to handle slave");
}
else
sql_print_error("Server id is not set, slave thread will not be started");
}
//printf(ER(ER_READY),my_progname,server_version,"");
printf("%s initialized.\n", server_version);
fflush(stdout);
}
void embedded_srv_deinit()
{
/* (void) pthread_attr_destroy(&connection_attrib); */
DBUG_PRINT("quit",("Exiting main thread"));
#ifdef EXTRA_DEBUG
sql_print_error("Before Lock_thread_count");
#endif
(void) pthread_mutex_lock(&LOCK_thread_count);
select_thread_in_use=0; // For close_connections
(void) pthread_cond_broadcast(&COND_thread_count);
(void) pthread_mutex_unlock(&LOCK_thread_count);
#ifdef EXTRA_DEBUG
sql_print_error("After lock_thread_count");
#endif
/* Wait until cleanup is done */
(void) pthread_mutex_lock(&LOCK_thread_count);
while (!ready_to_exit)
{
pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
}
(void) pthread_mutex_unlock(&LOCK_thread_count);
my_thread_end();
}
}
int embedded_do_command(NET * net)
{
THD * thd = (THD *) net ->vio;
do_command(thd);
return 0;
}

236
libmysqld/lib_vio.c Normal file
View File

@ -0,0 +1,236 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA */
/*
Note that we can't have assertion on file descriptors; The reason for
this is that during mysql shutdown, another thread can close a file
we are working on. In this case we should just return read errors from
the file descriptior.
*/
#include <global.h>
#ifndef HAVE_VIO /* is Vio suppored by the Vio lib ? */
#include <errno.h>
#include <my_sys.h>
#include "mysql.h"
#include <violite.h>
#include <my_sys.h>
#include <my_net.h>
#include <m_string.h>
#include <dbug.h>
#include <assert.h>
#if defined(__EMX__)
#include <sys/ioctl.h>
#define ioctlsocket(A,B,C) ioctl((A),(B),(void *)(C),sizeof(*(C)))
#undef HAVE_FCNTL
#endif /* defined(__EMX__) */
#if defined(MSDOS) || defined(__WIN__)
#ifdef __WIN__
#undef errno
#undef EINTR
#undef EAGAIN
#define errno WSAGetLastError()
#define EINTR WSAEINTR
#define EAGAIN WSAEINPROGRESS
#endif /* __WIN__ */
#define O_NONBLOCK 1 /* For emulation of fcntl() */
#endif
#ifndef EWOULDBLOCK
#define EWOULDBLOCK EAGAIN
#endif
#ifndef __WIN__
#define HANDLE void *
#endif
struct st_vio
{
my_socket sd; /* my_socket - real or imaginary */
HANDLE hPipe;
my_bool localhost; /* Are we from localhost? */
int fcntl_mode; /* Buffered fcntl(sd,F_GETFL) */
struct sockaddr_in local; /* Local internet address */
struct sockaddr_in remote; /* Remote internet address */
enum enum_vio_type type; /* Type of connection */
char desc[30]; /* String description */
/* #ifdef EMBEDDED_LIBRARY */
/* void *dest_net; */
void *dest_thd;
char *packets, **last_packet;
char *where_in_packet, *end_of_packet;
my_bool reading;
MEM_ROOT root;
/* #endif */
};
/* Initialize the communication buffer */
Vio *vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost)
{
Vio * vio = NULL;
vio = (Vio *) my_malloc (sizeof(*vio),MYF(MY_WME|MY_ZEROFILL));
if (vio)
{
init_alloc_root(&vio->root, 8192, 1024);
vio->root.min_malloc = sizeof(char *) + 4;
vio->last_packet = &vio->packets;
}
return (vio);
}
#ifdef __WIN__
Vio *vio_new_win32pipe(HANDLE hPipe)
{
return (NULL);
}
#endif
void vio_delete(Vio * vio)
{
if (vio)
{
if (vio->type != VIO_CLOSED) vio_close(vio);
free_root(&vio->root, MYF(0));
my_free((gptr)vio, MYF(0));
}
}
void vio_reset(Vio *vio)
{
free_root(&vio->root, MYF(MY_KEEP_PREALLOC));
vio->packets = vio->where_in_packet = vio->end_of_packet = 0;
vio->last_packet = &vio->packets;
}
int vio_errno(Vio *vio __attribute__((unused)))
{
return errno; /* On Win32 this mapped to WSAGetLastError() */
}
int vio_read(Vio * vio, gptr buf, int size)
{
vio->reading = 1;
if (vio->where_in_packet >= vio->end_of_packet)
{
dbug_assert(vio->packets);
vio->where_in_packet = vio->packets + sizeof(char *) + 4;
vio->end_of_packet = vio->where_in_packet +
uint4korr(vio->packets + sizeof(char *));
vio->packets = *(char **)vio->packets;
}
memcpy(buf, vio->where_in_packet, size);
vio->where_in_packet += size;
return (size);
}
int vio_write(Vio * vio, const gptr buf, int size)
{
char *packet;
if (vio->reading)
{
vio->reading = 0;
vio_reset(vio);
}
if ((packet = alloc_root(&vio->root, sizeof(char*) + 4 + size)))
{
*vio->last_packet = packet;
vio->last_packet = (char **)packet;
*((char **)packet) = 0; /* safety */
packet += sizeof(char *);
int4store(packet, size);
memcpy(packet + 4, buf, size);
}
else
size=0;
return (size);
}
int vio_blocking(Vio * vio, my_bool set_blocking_mode)
{
int r=0;
return (r);
}
my_bool
vio_is_blocking(Vio * vio)
{
my_bool r=0;
return(r);
}
int vio_fastsend(Vio * vio)
{
int r=0;
return(r);
}
int vio_keepalive(Vio* vio, my_bool set_keep_alive)
{
int r=0;
return (r);
}
my_bool
vio_should_retry(Vio * vio __attribute__((unused)))
{
int en = errno;
return en == EAGAIN || en == EINTR || en == EWOULDBLOCK;
}
int vio_close(Vio * vio)
{
int r=0;
return(r);
}
const char *vio_description(Vio * vio)
{
return "embedded vio";
}
enum enum_vio_type vio_type(Vio* vio)
{
return VIO_CLOSED;
}
my_socket vio_fd(Vio* vio)
{
return 0;
}
my_bool vio_peer_addr(Vio * vio, char *buf)
{
return(0);
}
void vio_in_addr(Vio *vio, struct in_addr *in)
{
}
#endif /* HAVE_VIO */

2299
libmysqld/libmysqld.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,15 @@
# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
#
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@ -17,7 +17,7 @@
EXTRA_DIST = mi_test_all.sh mi_test_all.res
pkgdata_DATA = mi_test_all mi_test_all.res
INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include
LDADD = @CLIENT_EXTRA_LDFLAGS@ libmyisam.a ../mysys/libmysys.a \
../dbug/libdbug.a ../strings/libmystrings.a
pkglib_LIBRARIES = libmyisam.a
@ -25,13 +25,14 @@ bin_PROGRAMS = myisamchk myisamlog myisampack
myisamchk_DEPENDENCIES= $(LIBRARIES)
myisamlog_DEPENDENCIES= $(LIBRARIES)
myisampack_DEPENDENCIES=$(LIBRARIES)
noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 ft_test1 ft_eval
noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 ft_test1 ft_eval ft_dump
noinst_HEADERS = myisamdef.h fulltext.h ftdefs.h ft_test1.h ft_eval.h
mi_test1_DEPENDENCIES= $(LIBRARIES)
mi_test2_DEPENDENCIES= $(LIBRARIES)
mi_test3_DEPENDENCIES= $(LIBRARIES)
ft_test1_DEPENDENCIES= $(LIBRARIES)
ft_eval_DEPENDENCIES= $(LIBRARIES)
ft_dump_DEPENDENCIES= $(LIBRARIES)
libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \
mi_rnext.c mi_rnext_same.c \
mi_search.c mi_page.c mi_key.c mi_locking.c \
@ -45,7 +46,7 @@ libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \
mi_changed.c mi_static.c mi_delete_all.c \
mi_delete_table.c mi_rename.c mi_check.c \
ft_parser.c ft_search.c ft_stopwords.c ft_static.c \
ft_update.c sort.c
ft_update.c ft_boolean_search.c ft_nlq_search.c sort.c
CLEANFILES = test?.MY? FT?.MY? isam.log mi_test_all
DEFS = -DMAP_TO_USE_RAID
# Omit dependency for ../mit-pthreads/include/sys that only exits if

222
myisam/ft_boolean_search.c Normal file
View File

@ -0,0 +1,222 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
#include "ftdefs.h"
/* search with boolean queries */
typedef struct st_all_in_one {
MI_INFO *info;
uint keynr;
uchar *keybuff;
MI_KEYDEF *keyinfo;
my_off_t key_root;
TREE dtree;
byte *start, *end;
uint total_yes, total_no;
} ALL_IN_ONE;
typedef struct st_ft_superdoc {
FT_DOC doc;
//FT_WORD *word_ptr;
//double tmp_weight;
uint yes;
uint no;
uint wno;
ALL_IN_ONE *aio;
} FT_SUPERDOC;
static int FT_SUPERDOC_cmp(FT_SUPERDOC *p1, FT_SUPERDOC *p2)
{
if (p1->doc.dpos < p2->doc.dpos)
return -1;
if (p1->doc.dpos == p2->doc.dpos)
return 0;
return 1;
}
static int walk_and_copy(FT_SUPERDOC *from,
uint32 count __attribute__((unused)), FT_DOC **to)
{
if (from->yes == from->aio->total_yes && !from->no)
{
(*to)->dpos=from->doc.dpos;
(*to)->weight=from->doc.weight;
(*to)++;
}
return 0;
}
static double _wghts[11]={
0.131687242798354,
0.197530864197531,
0.296296296296296,
0.444444444444444,
0.666666666666667,
1.000000000000000,
1.500000000000000,
2.250000000000000,
3.375000000000000,
5.062500000000000,
7.593750000000000};
static double *wghts=_wghts+5; // wghts[i] = 1.5**i
static double _nwghts[11]={
-0.065843621399177,
-0.098765432098766,
-0.148148148148148,
-0.222222222222222,
-0.333333333333334,
-0.500000000000000,
-0.750000000000000,
-1.125000000000000,
-1.687500000000000,
-2.531250000000000,
-3.796875000000000};
static double *nwghts=_nwghts+5; // nwghts[i] = -0.5*1.5**i
int do_boolean(ALL_IN_ONE *aio, uint nested,
int yesno, int plusminus, bool pmsign)
{
int r, res;
uint keylen, wno;
FT_SUPERDOC sdoc, *sptr;
TREE_ELEMENT *selem;
FT_WORD w;
FTB_PARAM param;
#ifdef EVAL_RUN
return 1;
#endif /* EVAL_RUN */
param.prev=' ';
for(wno=1; res=ft_get_word(&aio->start,aio->end,&w,&param); wno++)
{
r=plusminus+param.plusminus;
if (param.pmsign^pmsign)
w.weight=nwghts[(r>5)?5:((r<-5)?-5:r)];
else
w.weight=wghts[(r>5)?5:((r<-5)?-5:r)];
if (param.yesno>0) aio->total_yes++;
if (param.yesno<0) aio->total_no++;
switch (res) {
case FTB_LBR: // (
//if (do_boolean(aio,nested+1,my_yesno,plusminus+my_plusminus))
// return 1;
// ???
break;
case 1: // word
keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,&w,0);
keylen-=HA_FT_WLEN;
r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen,
SEARCH_FIND | SEARCH_PREFIX, aio->key_root);
while (!r)
{
if (param.trunc)
r=_mi_compare_text(default_charset_info,
aio->info->lastkey+1,keylen-1,
aio->keybuff+1,keylen-1,0);
else
r=_mi_compare_text(default_charset_info,
aio->info->lastkey,keylen,
aio->keybuff,keylen,0);
if (r) break;
sdoc.doc.dpos=aio->info->lastpos;
/* saving document matched into dtree */
if (!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1;
sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem);
if (selem->count==1) /* document's first match */
{
sptr->yes=sptr->no=sptr->doc.weight=0;
sptr->aio=aio;
sptr->wno=0;
}
if (sptr->wno != wno)
{
if (param.yesno>0) sptr->yes++;
if (param.yesno<0) sptr->no++;
sptr->wno=wno;
}
sptr->doc.weight+=w.weight;
if (_mi_test_if_changed(aio->info) == 0)
r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey,
aio->info->lastkey_length, SEARCH_BIGGER,
aio->key_root);
else
r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey,
aio->info->lastkey_length, SEARCH_BIGGER,
aio->key_root);
}
break;
case FTB_RBR: // )
break;
}
}
return 0;
}
FT_DOCLIST *ft_boolean_search(MI_INFO *info, uint keynr, byte *query,
uint query_len)
{
ALL_IN_ONE aio;
FT_DOC *dptr;
FT_DOCLIST *dlist=NULL;
aio.info=info;
aio.keynr=keynr;
aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length;
aio.keyinfo=aio.info->s->keyinfo+keynr;
aio.key_root=aio.info->s->state.key_root[keynr];
aio.start=query;
aio.end=query+query_len;
aio.total_yes=aio.total_no=0;
init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0,
NULL);
if (do_boolean(&aio,0,0,0,0))
goto err;
dlist=(FT_DOCLIST *)my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1),MYF(0));
if(!dlist)
goto err;
dlist->ndocs=aio.dtree.elements_in_tree;
dlist->curdoc=-1;
dlist->info=aio.info;
dptr=dlist->doc;
tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr, left_root_right);
dlist->ndocs=dptr - dlist->doc;
err:
delete_tree(&aio.dtree);
return dlist;
}

214
myisam/ft_dump.c Normal file
View File

@ -0,0 +1,214 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
#include "ftdefs.h"
static void get_options(int argc,char *argv[]);
static void usage(char *argv[]);
static void complain(int val);
static int count=0, stats=0, dump=0, verbose=0;
static char *query=NULL;
#define MAX (MAX_WORD_LEN+10)
#define HOW_OFTEN_TO_WRITE 1000
int main(int argc,char *argv[])
{
int error=0;
uint keylen, inx, doc_cnt;
float weight;
double gws, min_gws, avg_gws=0;
MI_INFO *info;
char buf[MAX], buf2[MAX], buf_maxlen[MAX], buf_min_gws[MAX], *s;
ulong total=0, maxlen=0, uniq=0, max_doc_cnt=0;
#ifdef EVAL_RUN
uint cnt;
double sum, sum2, suml;
#endif /* EVAL_RUN */
struct { MI_INFO *info; } aio0, *aio=&aio0; /* for GWS_IN_USE */
MY_INIT(argv[0]);
get_options(argc,argv);
if (count || dump)
verbose=0;
else
stats=1;
if (verbose)
setbuf(stdout,NULL);
if (argc-optind < 2)
usage(argv);
if (!(info=mi_open(argv[optind],2,HA_OPEN_ABORT_IF_LOCKED)))
goto err;
inx=atoi(argv[optind+1]);
*buf2=0;
aio->info=info;
if ((inx >= info->s->base.keys) || !(info->s->keyinfo[inx].flag & HA_FULLTEXT))
{
printf("Key %d in table %s is not a FULLTEXT key\n", inx, info->filename);
goto err;
}
if (query)
{
FT_DOCLIST *result;
int i;
ft_init_stopwords(ft_precompiled_stopwords);
result=ft_init_search(info,inx,query,strlen(query),1);
if(!result)
goto err;
if (verbose)
printf("%d rows matched\n",result->ndocs);
for(i=0 ; i<result->ndocs ; i++)
printf("%9qx %20.7f\n",result->doc[i].dpos,result->doc[i].weight);
ft_close_search(result);
}
else
{
info->lastpos= HA_OFFSET_ERROR;
info->update|= HA_STATE_PREV_FOUND;
while (!(error=mi_rnext(info,NULL,inx)))
{
keylen=*(info->lastkey);
#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
#ifdef EVAL_RUN
mi_float4get(weight,info->lastkey+keylen+2);
#else /* EVAL_RUN */
mi_float4get(weight,info->lastkey+keylen+1);
#endif /* EVAL_RUN */
#else
#error
#endif
#ifdef EVAL_RUN
cnt=*(byte *)(info->lastkey+keylen);
#endif /* EVAL_RUN */
snprintf(buf,MAX,"%.*s",keylen,info->lastkey+1);
for (s=buf;*s;s++) *s=tolower(*s);
total++;
if (count || stats)
{
doc_cnt++;
#ifdef EVAL_RUN
sum +=cnt;
sum2+=cnt*cnt;
suml+=cnt*log(cnt);
#endif /* EVAL_RUN */
if (strcmp(buf, buf2))
{
if (*buf2)
{
uniq++;
avg_gws+=gws=GWS_IN_USE;
if (count)
printf("%9u %20.7f %s\n",doc_cnt,gws,buf2);
if (maxlen<keylen)
{
maxlen=keylen;
strcpy(buf_maxlen, buf2);
}
if (max_doc_cnt < doc_cnt)
{
max_doc_cnt=doc_cnt;
strcpy(buf_min_gws, buf2);
min_gws=gws;
}
}
strcpy(buf2, buf);
#ifdef EVAL_RUN
sum=sum2=suml=
#endif /* EVAL_RUN */
doc_cnt=0;
}
}
if (dump)
printf("%9qx %20.7f %s\n",info->lastpos,weight,buf);
if(verbose && (total%HOW_OFTEN_TO_WRITE)==0)
printf("%10ld\r",total);
}
if (stats)
printf("Total rows: %qu\nTotal words: %lu\n"
"Unique words: %lu\nLongest word: %lu chars (%s)\n"
"Average global weight: %f\n"
"Most common word: %lu times, weight: %f (%s)\n",
(ulonglong)info->state->records, total, uniq, maxlen, buf_maxlen,
avg_gws/uniq, max_doc_cnt, min_gws, buf_min_gws);
}
err:
if (error && error != HA_ERR_END_OF_FILE)
printf("got error %d\n",my_errno);
if (info)
mi_close(info);
return 0;
}
const char *options="dscve:h";
static void get_options(int argc, char *argv[])
{
int c;
while ((c=getopt(argc,argv,options)) != -1)
{
switch(c) {
case 'd': dump=1; complain(count || query); break;
case 's': stats=1; complain(query!=0); break;
case 'v': verbose=1; break;
case 'c': count=1; complain(dump || query); break;
case 'e': query=my_strdup(optarg,MYF(MY_FAE)); complain(dump || count || stats); break;
case '?':
case 'h':
default:
usage(argv);
}
}
return;
} /* get options */
static void usage(char *argv[])
{
printf("Use: %s [-%s] <table_name> <key_no>\n", *argv, options);
exit(1);
}
static void complain(int val) /* Kinda assert :-) */
{
if (val)
{
printf("You cannot use these options together!\n");
exit(1);
}
}

191
myisam/ft_nlq_search.c Normal file
View File

@ -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 */
/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
#include "ftdefs.h"
/* search with natural language queries */
typedef struct st_all_in_one {
MI_INFO *info;
uint keynr;
uchar *keybuff;
MI_KEYDEF *keyinfo;
my_off_t key_root;
TREE dtree;
} ALL_IN_ONE;
typedef struct st_ft_superdoc {
FT_DOC doc;
FT_WORD *word_ptr;
double tmp_weight;
} FT_SUPERDOC;
static int FT_SUPERDOC_cmp(FT_SUPERDOC *p1, FT_SUPERDOC *p2)
{
if (p1->doc.dpos < p2->doc.dpos)
return -1;
if (p1->doc.dpos == p2->doc.dpos)
return 0;
return 1;
}
static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
{
uint keylen, r, doc_cnt;
#ifdef EVAL_RUN
uint cnt;
double sum, sum2, suml;
#endif /* EVAL_RUN */
FT_SUPERDOC sdoc, *sptr;
TREE_ELEMENT *selem;
#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
float tmp_weight;
#else
#error
#endif
word->weight=LWS_FOR_QUERY;
keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,word,0);
#ifdef EVAL_RUN
keylen-=1+HA_FT_WLEN;
#else /* EVAL_RUN */
keylen-=HA_FT_WLEN;
#endif /* EVAL_RUN */
#ifdef EVAL_RUN
sum=sum2=suml=
#endif /* EVAL_RUN */
doc_cnt=0;
r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen,
SEARCH_FIND | SEARCH_PREFIX, aio->key_root);
while(!r)
{
if (_mi_compare_text(default_charset_info,
aio->info->lastkey,keylen,
aio->keybuff,keylen,0)) break;
#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
#ifdef EVAL_RUN
mi_float4get(tmp_weight,aio->info->lastkey+keylen+1);
#else /* EVAL_RUN */
mi_float4get(tmp_weight,aio->info->lastkey+keylen);
#endif /* EVAL_RUN */
#else
#error
#endif
if(tmp_weight==0) return doc_cnt; /* stopword, doc_cnt should be 0 */
#ifdef EVAL_RUN
cnt=*(byte *)(aio->info->lastkey+keylen);
#endif /* EVAL_RUN */
sdoc.doc.dpos=aio->info->lastpos;
/* saving document matched into dtree */
if(!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1;
sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem);
if(selem->count==1) /* document's first match */
sptr->doc.weight=0;
else
sptr->doc.weight+=sptr->tmp_weight*sptr->word_ptr->weight;
sptr->word_ptr=word;
sptr->tmp_weight=tmp_weight;
doc_cnt++;
#ifdef EVAL_RUN
sum +=cnt;
sum2+=cnt*cnt;
suml+=cnt*log(cnt);
#endif /* EVAL_RUN */
if (_mi_test_if_changed(aio->info) == 0)
r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey,
aio->info->lastkey_length, SEARCH_BIGGER,
aio->key_root);
else
r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey,
aio->info->lastkey_length, SEARCH_BIGGER,
aio->key_root);
}
if(doc_cnt) {
word->weight*=GWS_IN_USE;
if(word->weight < 0) word->weight=0;
}
return 0;
}
static int walk_and_copy(FT_SUPERDOC *from,
uint32 count __attribute__((unused)), FT_DOC **to)
{
from->doc.weight+=from->tmp_weight*from->word_ptr->weight;
(*to)->dpos=from->doc.dpos;
(*to)->weight=from->doc.weight;
(*to)++;
return 0;
}
FT_DOCLIST *ft_nlq_search(MI_INFO *info, uint keynr, byte *query,
uint query_len)
{
TREE *wtree, allocated_wtree;
ALL_IN_ONE aio;
FT_DOC *dptr;
FT_DOCLIST *dlist=NULL;
aio.info=info;
aio.keynr=keynr;
aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length;
aio.keyinfo=aio.info->s->keyinfo+keynr;
aio.key_root=aio.info->s->state.key_root[keynr];
bzero(&allocated_wtree,sizeof(allocated_wtree));
init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0,
NULL);
if(!(wtree=ft_parse(&allocated_wtree,query,query_len)))
return NULL;
if(tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio,
left_root_right))
goto err;
dlist=(FT_DOCLIST *)my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1),MYF(0));
if(!dlist)
goto err;
dlist->ndocs=aio.dtree.elements_in_tree;
dlist->curdoc=-1;
dlist->info=aio.info;
dptr=dlist->doc;
tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr, left_root_right);
err:
delete_tree(wtree);
delete_tree(&aio.dtree);
return dlist;
}

View File

@ -83,13 +83,12 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree)
tree_walk(wtree,(tree_walk_action)&walk_and_copy,&docstat,left_root_right);
}
delete_tree(wtree);
my_free((char*) wtree,MYF(0));
if (!wlist)
return NULL;
docstat.list->pos=NULL;
for(p=wlist;p->pos;p++)
for (p=wlist;p->pos;p++)
{
p->weight=PRENORM_IN_USE;
#ifdef EVAL_RUN
@ -104,7 +103,7 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree)
#endif
#endif /* EVAL_RUN */
for(p=wlist;p->pos;p++)
for (p=wlist;p->pos;p++)
{
p->weight/=NORM_IN_USE;
}
@ -112,40 +111,133 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree)
return wlist;
}
#define true_word_char(X) (isalnum(X) || (X)=='_')
#ifdef HYPHEN_IS_DELIM
#define word_char(X) (isalnum(X) || (X)=='_' || (X)=='\'')
#define misc_word_char(X) ((X)=='\'')
#else
#define word_char(X) (isalnum(X) || (X)=='_' || (X)=='\'' || (X)=='-')
#define misc_word_char(X) ((X)=='\'' || (X)=='-')
#endif
#define word_char(X) (true_word_char(X) || misc_word_char(X))
/* this is rather dumb first version of the parser */
TREE * ft_parse(TREE *wtree, byte *doc, int doclen)
byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param)
{
byte *end=doc+doclen;
FT_WORD w;
byte *doc=*start;
int mwc;
if (!wtree)
{
if (!(wtree=(TREE *)my_malloc(sizeof(TREE),MYF(0)))) return NULL;
init_tree(wtree,0,sizeof(FT_WORD),(qsort_cmp)&FT_WORD_cmp,0,NULL);
}
param->yesno=param->plusminus=param->pmsign=0;
w.weight=0;
while (doc<end)
{
for (;doc<end;doc++)
if (word_char(*doc)) break;
for (w.pos=doc; doc<end; doc++)
if (!word_char(*doc)) break;
if ((w.len= (uint) (doc-w.pos)) < MIN_WORD_LEN) continue;
if (w.len >= HA_FT_MAXLEN) continue;
if (is_stopword(w.pos, w.len)) continue;
if (!tree_insert(wtree, &w, 0))
{
delete_tree(wtree);
my_free((char*) wtree,MYF(0));
return NULL;
if (true_word_char(*doc)) break;
if (*doc == FTB_LBR || *doc == FTB_RBR)
{
param->prev=' ';
*start=doc+1;
return *doc;
}
if (param->prev == ' ')
{
switch (*doc) {
case FTB_YES: param->yesno=+1; continue;
case FTB_NO: param->yesno=-1; continue;
case FTB_INC: param->plusminus++; continue;
case FTB_DEC: param->plusminus--; continue;
case FTB_NEG: param->pmsign=!param->pmsign; continue;
default: break;
}
}
param->prev=*doc;
param->yesno=param->plusminus=param->pmsign=0;
}
mwc=0;
for (word->pos=doc; doc<end; doc++)
if (true_word_char(*doc))
mwc=0;
else if (!misc_word_char(*doc) || mwc++)
break;
param->prev='A'; // be sure *prev is true_word_char
word->len= (uint)(doc-word->pos) - mwc;
if (param->trunc=(doc<end && *doc == FTB_TRUNC))
doc++;
if (word->len >= MIN_WORD_LEN && word->len < MAX_WORD_LEN &&
!is_stopword(word->pos, word->len))
{
*start=doc;
return 1;
}
}
return wtree;
return 0;
}
byte ft_simple_get_word(byte **start, byte *end, FT_WORD *word)
{
byte *doc=*start;
int mwc;
while (doc<end)
{
for (;doc<end;doc++)
{
if (true_word_char(*doc)) break;
}
mwc=0;
for(word->pos=doc; doc<end; doc++)
if (true_word_char(*doc))
mwc=0;
else if (!misc_word_char(*doc) || mwc++)
break;
word->len= (uint)(doc-word->pos) - mwc;
if (word->len >= MIN_WORD_LEN && word->len < MAX_WORD_LEN &&
!is_stopword(word->pos, word->len))
{
*start=doc;
return 1;
}
}
return 0;
}
int is_boolean(byte *q, uint len)
{
if (!len) return 0;
if (*q == FTB_YES || *q == FTB_NO) return 1;
for (++q; --len; ++q)
{
if ((*q == FTB_YES || *q == FTB_NO) && q[-1] == ' ' && true_word_char(q[1]))
return 1;
}
return 0;
}
TREE * ft_parse(TREE *wtree, byte *doc, int doclen)
{
byte *end=doc+doclen;
int res;
FT_WORD w;
if (!is_tree_inited(wtree))
{
init_tree(wtree,0,sizeof(FT_WORD),(qsort_cmp)&FT_WORD_cmp,0,NULL);
}
while (res=ft_simple_get_word(&doc,end,&w))
{
if (!tree_insert(wtree, &w, 0))
goto err;
}
return wtree;
err:
delete_tree(wtree);
return NULL;
}

View File

@ -18,146 +18,17 @@
#include "ftdefs.h"
/* queries isam and returns list of documents matched */
typedef struct st_all_in_one {
MI_INFO *info;
uint keynr;
uchar *keybuff;
MI_KEYDEF *keyinfo;
my_off_t key_root;
TREE dtree;
} ALL_IN_ONE;
typedef struct st_ft_superdoc {
FT_DOC doc;
FT_WORD *word_ptr;
double tmp_weight;
} FT_SUPERDOC;
static int FT_SUPERDOC_cmp(FT_SUPERDOC *p1, FT_SUPERDOC *p2)
{
if (p1->doc.dpos < p2->doc.dpos)
return -1;
if (p1->doc.dpos == p2->doc.dpos)
return 0;
return 1;
}
static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
{
uint keylen, r, doc_cnt;
#ifdef EVAL_RUN
uint cnt;
double sum, sum2, suml;
#endif /* EVAL_RUN */
FT_SUPERDOC sdoc, *sptr;
TREE_ELEMENT *selem;
#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
float tmp_weight;
#else
#error
#endif
word->weight=LWS_FOR_QUERY;
keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,word,0);
#ifdef EVAL_RUN
keylen-=1+HA_FT_WLEN;
#else /* EVAL_RUN */
keylen-=HA_FT_WLEN;
#endif /* EVAL_RUN */
#ifdef EVAL_RUN
sum=sum2=suml=
#endif /* EVAL_RUN */
doc_cnt=0;
r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen,
SEARCH_FIND | SEARCH_PREFIX, aio->key_root);
while(!r)
{
if (_mi_compare_text(default_charset_info,
aio->info->lastkey,keylen,
aio->keybuff,keylen,0)) break;
#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
#ifdef EVAL_RUN
mi_float4get(tmp_weight,aio->info->lastkey+keylen+1);
#else /* EVAL_RUN */
mi_float4get(tmp_weight,aio->info->lastkey+keylen);
#endif /* EVAL_RUN */
#else
#error
#endif
if(tmp_weight==0) return doc_cnt; /* stopword, doc_cnt should be 0 */
#ifdef EVAL_RUN
cnt=*(byte *)(aio->info->lastkey+keylen);
#endif /* EVAL_RUN */
sdoc.doc.dpos=aio->info->lastpos;
/* saving document matched into dtree */
if(!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1;
sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem);
if(selem->count==1) /* document's first match */
sptr->doc.weight=0;
else
sptr->doc.weight+=sptr->tmp_weight*sptr->word_ptr->weight;
sptr->word_ptr=word;
sptr->tmp_weight=tmp_weight;
doc_cnt++;
#ifdef EVAL_RUN
sum +=cnt;
sum2+=cnt*cnt;
suml+=cnt*log(cnt);
#endif /* EVAL_RUN */
if (_mi_test_if_changed(aio->info) == 0)
r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey,
aio->info->lastkey_length, SEARCH_BIGGER,
aio->key_root);
else
r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey,
aio->info->lastkey_length, SEARCH_BIGGER,
aio->key_root);
}
if(doc_cnt) {
word->weight*=GWS_IN_USE;
if(word->weight < 0) word->weight=0;
}
return 0;
}
static int walk_and_copy(FT_SUPERDOC *from,
uint32 count __attribute__((unused)), FT_DOC **to)
{
from->doc.weight+=from->tmp_weight*from->word_ptr->weight;
(*to)->dpos=from->doc.dpos;
(*to)->weight=from->doc.weight;
(*to)++;
return 0;
}
/* queries myisam and returns list of documents matched */
static int FT_DOC_cmp(FT_DOC *a, FT_DOC *b)
{
return sgn(b->weight - a->weight);
}
FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key,
uint key_len, my_bool presort)
FT_DOCLIST *ft_init_search(void *info, uint keynr, byte *query,
uint query_len, my_bool presort)
{
TREE *wtree;
ALL_IN_ONE aio;
FT_DOCLIST *dlist;
FT_DOC *dptr;
my_off_t saved_lastpos=((MI_INFO *)info)->lastpos;
/* black magic ON */
@ -167,44 +38,16 @@ FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key,
return NULL;
/* black magic OFF */
dlist=NULL;
aio.info=(MI_INFO *)info;
aio.keynr=keynr;
aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length;
aio.keyinfo=aio.info->s->keyinfo+keynr;
aio.key_root=aio.info->s->state.key_root[keynr];
if (is_boolean(query, query_len))
dlist=ft_boolean_search(info,keynr,query,query_len);
else
dlist=ft_nlq_search(info,keynr,query,query_len);
if (!(wtree=ft_parse(NULL,key,key_len))) return NULL;
init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0,
NULL);
if (tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio,
left_root_right))
goto err;
dlist=(FT_DOCLIST *) my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*
(aio.dtree.elements_in_tree-1),MYF(0));
if (!dlist)
goto err;
dlist->ndocs=aio.dtree.elements_in_tree;
dlist->curdoc=-1;
dlist->info=aio.info;
dptr=dlist->doc;
tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr,
left_root_right);
if (presort)
if(dlist && presort)
{
qsort(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort_cmp)&FT_DOC_cmp);
}
err:
delete_tree(&aio.dtree);
delete_tree(wtree);
my_free((char*) wtree,MYF(0));
((MI_INFO *)info)->lastpos=saved_lastpos;
return dlist;
}

View File

@ -29,14 +29,16 @@
/* parses a document i.e. calls _mi_ft_parse for every keyseg */
static FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf,
FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf,
const byte *record)
{
TREE *parsed=NULL;
TREE *parsed, ptree;
MI_KEYSEG *keyseg;
byte *pos;
uint i;
bzero(parsed=&ptree, sizeof(ptree));
keyseg=info->s->keyinfo[keynr].seg;
for (i=info->s->keyinfo[keynr].keysegs-FT_SEGS ; i-- ; )
{
@ -64,7 +66,7 @@ static FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf,
return NULL;
}
/* Handle the case where all columns are NULL */
if (!parsed && !(parsed=ft_parse(0, (byte*) "", 0)))
if (!is_tree_inited(parsed) && !(parsed=ft_parse(parsed, (byte*) "", 0)))
return NULL;
return ft_linearize(info, keynr, keybuf, parsed);
}
@ -151,6 +153,69 @@ int _mi_ft_cmp(MI_INFO *info, uint keynr, const byte *rec1, const byte *rec2)
return GEE_THEY_ARE_ABSOLUTELY_IDENTICAL;
}
/* update a document entry */
int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf,
const byte *oldrec, const byte *newrec, my_off_t pos)
{
int error= -1;
FT_WORD *oldlist,*newlist, *old_word, *new_word;
uint key_length;
uint cmp;
if (!(old_word=oldlist=_mi_ft_parserecord(info, keynr, keybuf, oldrec)))
goto err0;
if (!(new_word=newlist=_mi_ft_parserecord(info, keynr, keybuf, newrec)))
goto err1;
while(old_word->pos && new_word->pos)
{
cmp=_mi_compare_text(default_charset_info,
(uchar*) old_word->pos,old_word->len,
(uchar*) new_word->pos,new_word->len,0);
if (cmp==0)
{
double p=(old_word->weight-new_word->weight)/
(old_word->weight+new_word->weight);
if (p<1e-5)
cmp=0;
else
cmp=sgn(p);
}
else
cmp=sgn(cmp);
switch (cmp) {
case -1:
key_length=_ft_make_key(info,keynr,keybuf,old_word,pos);
if (error=_mi_ck_delete(info,keynr,(uchar*) keybuf,key_length))
goto err2;
old_word++;
break;
case 0:
old_word++;
new_word++;
break;
case 1:
key_length=_ft_make_key(info,keynr,keybuf,new_word,pos);
if (error=_mi_ck_write(info,keynr,(uchar*) keybuf,key_length))
goto err2;
new_word++;
break;
}
}
if (old_word->pos)
error=_mi_ft_erase(info,keynr,keybuf,old_word,pos);
else if (new_word->pos)
error=_mi_ft_store(info,keynr,keybuf,new_word,pos);
err2:
my_free((char*) newlist,MYF(0));
err1:
my_free((char*) oldlist,MYF(0));
err0:
return error;
}
/* adds a document to the collection */
int _mi_ft_add(MI_INFO *info, uint keynr, byte *keybuf, const byte *record,
my_off_t pos)

View File

@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
@ -23,14 +23,21 @@
#include <my_tree.h>
#define MIN_WORD_LEN 4
#define MAX_WORD_LEN HA_FT_MAXLEN
#define MAX_WORD_LEN_FOR_SORT 20
#define HYPHEN_IS_DELIM
#define HYPHEN_IS_CONCAT /* not used for now */
#define COMPILE_STOPWORDS_IN
/* Most of the formulae were shamelessly stolen from SMART distribution
ftp://ftp.cs.cornell.edu/pub/smart/smart.11.0.tar.Z
/* Interested readers may consult SMART
(ftp://ftp.cs.cornell.edu/pub/smart/smart.11.0.tar.Z)
for an excellent implementation of vector space model we use.
It also demonstrate the usage of different weghting techniques.
This code, though, is completely original and is not based on the
SMART code but was in some cases inspired by it.
NORM_PIVOT was taken from the article
A.Singhal, C.Buckley, M.Mitra, "Pivoted Document Length Normalization",
ACM SIGIR'96, 21-29, 1996
@ -82,6 +89,19 @@ extern ulong collstat;
#define GWS_ENTROPY (1-(suml/sum-log(sum))/log(aio->info->state->records))
/*=================================================================*/
/* Boolean search operators */
#define FTB_YES '+'
#define FTB_NO '-'
#define FTB_INC '>'
#define FTB_DEC '<'
#define FTB_LBR '('
#define FTB_RBR ')'
#define FTB_NEG '~'
#define FTB_TRUNC '*'
// #define FTB_MAX_SUBEXPR 255
// #define FTB_MAX_DEPTH 16
typedef struct st_ft_word {
byte * pos;
uint len;
@ -91,9 +111,26 @@ typedef struct st_ft_word {
#endif /* EVAL_RUN */
} FT_WORD;
typedef struct st_ftb_param {
byte prev;
int yesno;
int plusminus;
bool pmsign;
bool trunc;
} FTB_PARAM;
int is_stopword(char *word, uint len);
int is_boolean(byte *q, uint len);
uint _ft_make_key(MI_INFO *, uint , byte *, FT_WORD *, my_off_t);
byte ft_get_word(byte **, byte *, FT_WORD *, FTB_PARAM *);
byte ft_simple_get_word(byte **, byte *, FT_WORD *);
TREE * ft_parse(TREE *, byte *, int);
FT_WORD * ft_linearize(MI_INFO *, uint, byte *, TREE *);
FT_WORD * _mi_ft_parserecord(MI_INFO *, uint , byte *, const byte *);
FT_DOCLIST * ft_nlq_search(MI_INFO *, uint, byte *, uint);
FT_DOCLIST * ft_boolean_search(MI_INFO *, uint, byte *, uint);

View File

@ -16,7 +16,7 @@
/* Descript, check and repair of ISAM tables */
#include "fulltext.h"
#include "ftdefs.h"
#include <m_ctype.h>
#include <stdarg.h>
#include <getopt.h>
@ -45,6 +45,7 @@ static int writekeys(MI_INFO *info,byte *buff,my_off_t filepos);
static int sort_one_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
my_off_t pagepos, File new_file);
static int sort_key_read(SORT_INFO *sort_info,void *key);
static int sort_ft_key_read(SORT_INFO *sort_info,void *key);
static int sort_get_next_record(SORT_INFO *sort_info);
static int sort_key_cmp(SORT_INFO *sort_info, const void *a,const void *b);
static int sort_key_write(SORT_INFO *sort_info, const void *a);
@ -53,7 +54,7 @@ static my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo,
static int sort_insert_key(MI_CHECK *param, reg1 SORT_KEY_BLOCKS *key_block,
uchar *key, my_off_t prev_block);
static int sort_delete_record(MI_CHECK *param);
static int flush_pending_blocks(MI_CHECK *param);
/*static int flush_pending_blocks(MI_CHECK *param);*/
static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint blocks,
uint buffer_length);
static void update_key_parts(MI_KEYDEF *keyinfo,
@ -1722,22 +1723,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
printf("Data records: %s\n", llstr(start_records,llbuff));
}
/* Hmm, repair_by_sort uses find_all_keys, and find_all_keys strictly
implies "one row - one key per keynr", while for ft_key one row/keynr
can produce as many keys as the number of unique words in the text
that's why I disabled repair_by_sort for ft-keys. (serg)
*/
for (i=0 ; i < share->base.keys ; i++)
{
if ((((ulonglong) 1 << i) & key_map) &&
(share->keyinfo[i].flag & HA_FULLTEXT))
{
mi_check_print_error(param,
"Can`t use repair_by_sort with FULLTEXT key");
DBUG_RETURN(1);
}
}
bzero((char*) sort_info,sizeof(*sort_info));
if (!(sort_info->key_block=
alloc_key_blocks(param,
@ -1829,6 +1814,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
param->read_cache.end_of_file=sort_info->filelength=
my_seek(param->read_cache.file,0L,MY_SEEK_END,MYF(0));
sort_info->wordlist=NULL;
if (share->data_file_type == DYNAMIC_RECORD)
length=max(share->base.min_pack_length+1,share->base.min_block_length);
else if (share->data_file_type == COMPRESSED_RECORD)
@ -1840,7 +1827,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
(ha_rows) (sort_info->filelength/length+1));
sort_param.key_cmp=sort_key_cmp;
sort_param.key_write=sort_key_write;
sort_param.key_read=sort_key_read;
sort_param.lock_in_memory=lock_memory;
sort_param.tmpdir=param->tmpdir;
sort_param.myf_rw=param->myf_rw;
@ -1886,6 +1872,17 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
info->state->records=info->state->del=share->state.split=0;
info->state->empty=0;
if (sort_info->keyinfo->flag & HA_FULLTEXT)
{
sort_param.max_records=sort_info->max_records=
(ha_rows) (sort_info->filelength/MAX_WORD_LEN_FOR_SORT+1);
sort_param.key_read=sort_ft_key_read;
sort_param.key_length+=MAX_WORD_LEN_FOR_SORT-MAX_WORD_LEN;
}
else
sort_param.key_read=sort_key_read;
if (_create_index_by_sort(&sort_param,
(my_bool) (!(param->testflag & T_VERBOSE)),
(uint) param->sort_buffer_length))
@ -1930,8 +1927,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
else
info->state->data_file_length=sort_info->max_pos;
if (flush_pending_blocks(param))
goto err;
/*if (flush_pending_blocks(param))
goto err;*/
param->read_cache.file=info->dfile; /* re-init read cache */
reinit_io_cache(&param->read_cache,READ_CACHE,share->pack.header_length,1,
@ -2055,11 +2052,52 @@ static int sort_key_read(SORT_INFO *sort_info, void *key)
"Found too many records; Can`t continue");
DBUG_RETURN(1);
}
(void) _mi_make_key(info,sort_info->key,key,sort_info->record,
sort_info->filepos);
sort_info->real_key_length=info->s->rec_reflength+_mi_make_key(info,
sort_info->key,key,sort_info->record,sort_info->filepos);
DBUG_RETURN(sort_write_record(sort_info));
} /* sort_key_read */
static int sort_ft_key_read(SORT_INFO *sort_info, void *key)
{
int error;
MI_INFO *info;
FT_WORD *wptr;
DBUG_ENTER("sort_ft_key_read");
info=sort_info->info;
if (!sort_info->wordlist)
{
do
{
if ((error=sort_get_next_record(sort_info)))
DBUG_RETURN(error);
if (!(wptr=_mi_ft_parserecord(info,sort_info->key,key,sort_info->record)))
DBUG_RETURN(1);
error=sort_write_record(sort_info);
}
while (!wptr->pos);
sort_info->wordptr=sort_info->wordlist=wptr;
}
else
{
error=0;
wptr=(FT_WORD*)(sort_info->wordptr);
}
sort_info->real_key_length=info->s->rec_reflength+_ft_make_key(info,
sort_info->key,key,wptr++,sort_info->filepos);
if (!wptr->pos)
{
my_free((char*) sort_info->wordlist, MYF(0));
sort_info->wordlist=0;
}
else
sort_info->wordptr=(void*)wptr;
DBUG_RETURN(error);
} /* sort_ft_key_read */
/* Read next record from file using parameters in sort_info */
/* Return -1 if end of file, 0 if ok and > 0 if error */
@ -2714,7 +2752,7 @@ static int sort_delete_record(MI_CHECK *param)
/* Fix all pending blocks and flush everything to disk */
static int flush_pending_blocks(MI_CHECK *param)
int flush_pending_blocks(MI_CHECK *param)
{
uint nod_flag,length;
my_off_t filepos,key_file_length;
@ -3181,15 +3219,7 @@ my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows,
return FALSE; /* Can't use sort */
for (i=0 ; i < share->base.keys ; i++,key++)
{
/* It's to disable repair_by_sort for ft-keys.
Another solution would be to make ft-keys just too_big_key_for_sort,
but then they won't be disabled by dectivate_non_unique_index
and so they will be created at the first stage. As ft-key creation
is very time-consuming process, it's better to leave it to repair stage
but this repair shouldn't be repair_by_sort (serg)
*/
if ((!force && mi_too_big_key_for_sort(key,rows)) ||
(key->flag & HA_FULLTEXT))
if (!force && mi_too_big_key_for_sort(key,rows))
return FALSE;
}
return TRUE;

View File

@ -625,15 +625,20 @@ static void setup_key_functions(register MI_KEYDEF *keyinfo)
}
else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
{
keyinfo->bin_search=_mi_seq_search;
keyinfo->get_key= _mi_get_pack_key;
if (keyinfo->seg[0].flag & HA_PACK_KEY)
{ /* Prefix compression */
if (!keyinfo->seg->charset || use_strcoll(keyinfo->seg->charset) ||
(keyinfo->seg->flag & HA_NULL_PART))
keyinfo->bin_search=_mi_seq_search;
else
keyinfo->bin_search=_mi_prefix_search;
keyinfo->pack_key=_mi_calc_var_pack_key_length;
keyinfo->store_key=_mi_store_var_pack_key;
}
else
{
keyinfo->bin_search=_mi_seq_search;
keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */
keyinfo->store_key=_mi_store_static_key;
}

File diff suppressed because it is too large Load Diff

View File

@ -98,9 +98,7 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
if ((int) i == info->lastinx)
key_changed|=HA_STATE_WRITTEN;
changed|=((ulonglong) 1 << i);
if (_mi_ft_del(info,i,(char*) old_key,oldrec,pos))
goto err;
if (_mi_ft_add(info,i,(char*) new_key,newrec,pos))
if (_mi_ft_update(info,i,(char*) old_key,oldrec,newrec,pos))
goto err;
}
}

View File

@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
@ -37,7 +37,7 @@ typedef struct st_mi_status_info
my_off_t key_empty; /* lost space in indexfile */
my_off_t key_file_length;
my_off_t data_file_length;
} MI_STATUS_INFO;
} MI_STATUS_INFO;
typedef struct st_mi_state_info
{
@ -285,7 +285,7 @@ struct st_myisam_info {
#define STATE_CHANGED 1
#define STATE_CRASHED 2
#define STATE_CRASHED_ON_REPAIR 4
#define STATE_CRASHED_ON_REPAIR 4
#define STATE_NOT_ANALYZED 8
#define STATE_NOT_OPTIMIZED_KEYS 16
#define STATE_NOT_SORTED_PAGES 32
@ -473,6 +473,9 @@ extern int _mi_bin_search(struct st_myisam_info *info,MI_KEYDEF *keyinfo,
extern int _mi_seq_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page,
uchar *key,uint key_len,uint comp_flag,
uchar **ret_pos,uchar *buff, my_bool *was_last_key);
extern int _mi_prefix_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page,
uchar *key,uint key_len,uint comp_flag,
uchar **ret_pos,uchar *buff, my_bool *was_last_key);
extern int _mi_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint ,
my_bool);
extern my_off_t _mi_kpos(uint nod_flag,uchar *after_key);
@ -640,6 +643,7 @@ int mi_open_keyfile(MYISAM_SHARE *share);
void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...));
void mi_check_print_warning _VARARGS((MI_CHECK *param, const char *fmt,...));
void mi_check_print_info _VARARGS((MI_CHECK *param, const char *fmt,...));
int flush_pending_blocks(MI_CHECK *param);
#ifdef __cplusplus
}

View File

@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
@ -19,7 +19,7 @@
them in sorted order through SORT_INFO functions.
*/
#include "myisamdef.h"
#include "fulltext.h"
#if defined(MSDOS) || defined(__WIN__)
#include <fcntl.h>
#else
@ -49,10 +49,12 @@ extern void print_error _VARARGS((const char *fmt,...));
static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info,uint keys,
uchar **sort_keys,
BUFFPEK *buffpek,int *maxbuffer,
IO_CACHE *tempfile);
DYNAMIC_ARRAY *buffpek,int *maxbuffer,
IO_CACHE *tempfile,
IO_CACHE *tempfile_for_exceptions);
static int NEAR_F write_keys(MI_SORT_PARAM *info,uchar * *sort_keys,
uint count, BUFFPEK *buffpek,IO_CACHE *tempfile);
static int NEAR_F write_key(MI_SORT_PARAM *info, uchar *key, IO_CACHE *tempfile);
static int NEAR_F write_index(MI_SORT_PARAM *info,uchar * *sort_keys,
uint count);
static int NEAR_F merge_many_buff(MI_SORT_PARAM *info,uint keys,
@ -67,7 +69,6 @@ static int NEAR_F merge_buffers(MI_SORT_PARAM *info,uint keys,
BUFFPEK *Fb, BUFFPEK *Tb);
static int NEAR_F merge_index(MI_SORT_PARAM *,uint,uchar **,BUFFPEK *, int,
IO_CACHE *);
static char **make_char_array(uint fields,uint length,myf my_flag);
/* Creates a index of sorted keys */
/* Returns 0 if everything went ok */
@ -77,15 +78,17 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
{
int error,maxbuffer,skr;
uint memavl,old_memavl,keys,sort_length;
BUFFPEK *buffpek;
DYNAMIC_ARRAY buffpek;
ha_rows records;
uchar **sort_keys;
IO_CACHE tempfile;
IO_CACHE tempfile, tempfile_for_exceptions;
DBUG_ENTER("_create_index_by_sort");
DBUG_PRINT("enter",("sort_length: %d", info->key_length));
my_b_clear(&tempfile);
buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1;
my_b_clear(&tempfile_for_exceptions);
bzero((char*) &buffpek,sizeof(buffpek));
sort_keys= (uchar **) NULL; error= 1;
maxbuffer=1;
memavl=max(sortbuff_size,MIN_SORT_MEMORY);
@ -113,14 +116,12 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
}
while ((maxbuffer= (int) (records/(keys-1)+1)) != skr);
if ((sort_keys= (uchar **) make_char_array(keys,sort_length,MYF(0))))
if (sort_keys=(uchar **)my_malloc(keys*(sort_length+sizeof(char*))+HA_FT_MAXLEN, MYF(0)))
{
if ((buffpek = (BUFFPEK*) my_malloc((uint) (sizeof(BUFFPEK)*
(uint) maxbuffer),
MYF(0))))
break;
else
if (init_dynamic_array(&buffpek, sizeof(BUFFPEK), maxbuffer, maxbuffer/2))
my_free((gptr) sort_keys,MYF(0));
else
break;
}
old_memavl=memavl;
if ((memavl=memavl/4*3) < MIN_SORT_MEMORY && old_memavl > MIN_SORT_MEMORY)
@ -136,7 +137,8 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
if (!no_messages)
printf(" - Searching for keys, allocating buffer for %d keys\n",keys);
if ((records=find_all_keys(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile))
if ((records=find_all_keys(info,keys,sort_keys,&buffpek,&maxbuffer,
&tempfile,&tempfile_for_exceptions))
== HA_POS_ERROR)
goto err; /* purecov: tested */
if (maxbuffer == 0)
@ -153,7 +155,8 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
{
if (!no_messages)
printf(" - Merging %lu keys\n",records); /* purecov: tested */
if (merge_many_buff(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile))
if (merge_many_buff(info,keys,sort_keys,
dynamic_element(&buffpek,0,BUFFPEK *),&maxbuffer,&tempfile))
goto err; /* purecov: inspected */
}
if (flush_io_cache(&tempfile) ||
@ -161,17 +164,39 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
goto err; /* purecov: inspected */
if (!no_messages)
puts(" - Last merge and dumping keys"); /* purecov: tested */
if (merge_index(info,keys,sort_keys,buffpek,maxbuffer,&tempfile))
if (merge_index(info,keys,sort_keys,dynamic_element(&buffpek,0,BUFFPEK *),
maxbuffer,&tempfile))
goto err; /* purecov: inspected */
}
if (flush_pending_blocks(info->sort_info->param))
goto err;
if (my_b_inited(&tempfile_for_exceptions))
{
MI_INFO *index=info->sort_info->info;
uint keyno=info->sort_info->key;
uint key_length, ref_length=index->s->rec_reflength;
if (flush_io_cache(&tempfile_for_exceptions) ||
reinit_io_cache(&tempfile_for_exceptions,READ_CACHE,0L,0,0))
goto err;
while (!my_b_read(&tempfile_for_exceptions,(byte*)&key_length, sizeof(key_length))
&& !my_b_read(&tempfile_for_exceptions,(byte*)sort_keys,(uint)key_length))
{
if (_mi_ck_write(index,keyno,(byte*)sort_keys,key_length-ref_length)) goto err;
}
}
error =0;
err:
if (sort_keys)
my_free((gptr) sort_keys,MYF(0));
if (buffpek)
my_free((gptr) buffpek,MYF(0));
delete_dynamic(&buffpek);
close_cached_file(&tempfile);
close_cached_file(&tempfile_for_exceptions);
DBUG_RETURN(error ? -1 : 0);
} /* _create_index_by_sort */
@ -180,36 +205,50 @@ err:
/* Search after all keys and place them in a temp. file */
static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys,
uchar **sort_keys, BUFFPEK *buffpek,
int *maxbuffer, IO_CACHE *tempfile)
uchar **sort_keys, DYNAMIC_ARRAY *buffpek,
int *maxbuffer, IO_CACHE *tempfile,
IO_CACHE *tempfile_for_exceptions)
{
int error;
uint idx,indexpos;
uint idx;
DBUG_ENTER("find_all_keys");
idx=indexpos=error=0;
idx=error=0;
sort_keys[0]=(char*)(sort_keys+keys);
while (!(error=(*info->key_read)(info->sort_info,sort_keys[idx])))
while(!(error=(*info->key_read)(info->sort_info,sort_keys[idx])))
{
if ((uint) ++idx == keys)
if (info->sort_info->real_key_length > info->key_length)
{
if (indexpos >= (uint) *maxbuffer ||
write_keys(info,sort_keys,idx-1,buffpek+indexpos,tempfile))
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
memcpy(sort_keys[0],sort_keys[idx-1],(size_t) info->key_length);
idx=1; indexpos++;
if (write_key(info,sort_keys[idx],tempfile_for_exceptions))
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
continue;
}
if (++idx == keys)
{
if (write_keys(info,sort_keys,idx-1,(BUFFPEK *)alloc_dynamic(buffpek),tempfile))
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
sort_keys[0]=(char*)(sort_keys+keys);
memcpy(sort_keys[0],sort_keys[idx-1],(size_t) info->key_length);
idx=1;
}
sort_keys[idx]=sort_keys[idx-1]+info->key_length;
}
if (error > 0)
DBUG_RETURN(HA_POS_ERROR); /* Aborted by get_key */ /* purecov: inspected */
if (indexpos)
if (indexpos >= (uint) *maxbuffer ||
write_keys(info,sort_keys,idx,buffpek+indexpos,tempfile))
if (buffpek->elements)
{
if (write_keys(info,sort_keys,idx,(BUFFPEK *)alloc_dynamic(buffpek),tempfile))
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
*maxbuffer=(int) indexpos;
DBUG_RETURN(indexpos*(keys-1)+idx);
} /* find_all_keys */
*maxbuffer=buffpek->elements-1;
}
else
*maxbuffer=0;
DBUG_RETURN((*maxbuffer)*(keys-1)+idx);
} /* find_all_keys */
/* Write all keys in memory to file for later merge */
@ -222,11 +261,12 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys,
DBUG_ENTER("write_keys");
qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp,
info->sort_info);
info->sort_info);
if (!my_b_inited(tempfile) &&
open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE,
info->myf_rw))
DBUG_RETURN(1); /* purecov: inspected */
buffpek->file_pos=my_b_tell(tempfile);
buffpek->count=count;
@ -237,6 +277,22 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys,
} /* write_keys */
static int NEAR_F write_key(MI_SORT_PARAM *info, uchar *key, IO_CACHE *tempfile)
{
uint key_length=info->sort_info->real_key_length;
DBUG_ENTER("write_key");
if (!my_b_inited(tempfile) &&
open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE,
info->myf_rw))
DBUG_RETURN(1);
if (my_b_write(tempfile,(byte*)&key_length,sizeof(key_length)) ||
my_b_write(tempfile,(byte*)key,(uint) key_length))
DBUG_RETURN(1);
DBUG_RETURN(0);
} /* write_key */
/* Write index */
static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys,
@ -326,7 +382,7 @@ static uint NEAR_F read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
/* If to_file == 0 then use info->key_write */
static int NEAR_F
merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
IO_CACHE *to_file, uchar **sort_keys, BUFFPEK *lastbuff,
BUFFPEK *Fb, BUFFPEK *Tb)
{
@ -472,21 +528,3 @@ merge_index(MI_SORT_PARAM *info, uint keys, uchar **sort_keys,
DBUG_RETURN(0);
} /* merge_index */
/* Make a pointer of arrays to keys */
static char **make_char_array(register uint fields, uint length, myf my_flag)
{
register char **pos;
char **old_pos,*char_pos;
DBUG_ENTER("make_char_array");
if ((old_pos= (char**) my_malloc( fields*(length+sizeof(char*)), my_flag)))
{
pos=old_pos; char_pos=((char*) (pos+fields)) -length;
while (fields--)
*(pos++) = (char_pos+= length);
}
DBUG_RETURN(old_pos);
} /* make_char_array */

View File

@ -112,6 +112,12 @@ while test $# -gt 0; do
--tmpdir=*) MYSQL_TMP_DIR=`$ECHO "$1" | $SED -e "s;--tmpdir=;;"` ;;
--master_port=*) MASTER_MYPORT=`$ECHO "$1" | $SED -e "s;--master_port=;;"` ;;
--slave_port=*) SLAVE_MYPORT=`$ECHO "$1" | $SED -e "s;--slave_port=;;"` ;;
--skip-innobase)
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-innobase"
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-innobase" ;;
--skip-bdb)
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-bdb"
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-bdb" ;;
--skip-rpl) NO_SLAVE=1 ;;
--record)
RECORD=1;

View File

@ -0,0 +1,10 @@
id tag value
1 foo123 bar111
2 foo123 bar222
3 bar345 baz333 ar
id_t2 id_t1 field_number
12346 3 1
2231626 64280 0
2231626 64281 0
id_t2
12346

View File

@ -0,0 +1,39 @@
#
# Test of fulltext index
# bug reported by Tibor Simko <tibor.simko@cern.ch>
#
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (
id mediumint unsigned NOT NULL auto_increment,
tag char(6) NOT NULL default '',
value text NOT NULL default '',
PRIMARY KEY (id),
KEY kt(tag),
KEY kv(value(15)),
FULLTEXT KEY kvf(value)
) TYPE=MyISAM;
DROP TABLE IF EXISTS t2;
CREATE TABLE t2 (
id_t2 mediumint unsigned NOT NULL default '0',
id_t1 mediumint unsigned NOT NULL default '0',
field_number tinyint unsigned NOT NULL default '0',
PRIMARY KEY (id_t2,id_t1,field_number),
KEY id_t1(id_t1)
) TYPE=MyISAM;
INSERT INTO t1 (tag,value) VALUES ('foo123','bar111');
INSERT INTO t2 VALUES (2231626,64280,0);
INSERT INTO t1 (tag,value) VALUES ('foo123','bar222');
INSERT INTO t2 VALUES (2231626,64281,0);
insert into t1 (tag,value) values ('bar345','baz333 ar');
insert into t2 values (12346, 3, 1);
select * from t1; select * from t2;
SELECT DISTINCT t2.id_t2
FROM t2, t1
WHERE MATCH (t1.value) AGAINST ('baz333')
AND t1.id = t2.id_t1;
DROP TABLE t1,t2;

25
pstack/Makefile.am Normal file
View File

@ -0,0 +1,25 @@
# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
INCLUDES = -I$(srcdir)/../include -I../include
pkglib_LIBRARIES = libpstack.a
noinst_HEADERS = bucomm.h debug.h ieee.h budbg.h demangle.h \
linuxthreads.h pstack.h pstacktrace.h
libpstack_a_SOURCES = bucomm.c filemode.c linuxthreads.c rddbg.c \
debug.c ieee.c pstack.c stabs.c
# Don't update the files from bitkeeper
%::SCCS/s.%

475
pstack/aout/aout64.h Normal file
View File

@ -0,0 +1,475 @@
/* `a.out' object-file definitions, including extensions to 64-bit fields */
#ifndef __A_OUT_64_H__
#define __A_OUT_64_H__
/* This is the layout on disk of the 32-bit or 64-bit exec header. */
#ifndef external_exec
struct external_exec
{
bfd_byte e_info[4]; /* magic number and stuff */
bfd_byte e_text[BYTES_IN_WORD]; /* length of text section in bytes */
bfd_byte e_data[BYTES_IN_WORD]; /* length of data section in bytes */
bfd_byte e_bss[BYTES_IN_WORD]; /* length of bss area in bytes */
bfd_byte e_syms[BYTES_IN_WORD]; /* length of symbol table in bytes */
bfd_byte e_entry[BYTES_IN_WORD]; /* start address */
bfd_byte e_trsize[BYTES_IN_WORD]; /* length of text relocation info */
bfd_byte e_drsize[BYTES_IN_WORD]; /* length of data relocation info */
};
#define EXEC_BYTES_SIZE (4 + BYTES_IN_WORD * 7)
/* Magic numbers for a.out files */
#if ARCH_SIZE==64
#define OMAGIC 0x1001 /* Code indicating object file */
#define ZMAGIC 0x1002 /* Code indicating demand-paged executable. */
#define NMAGIC 0x1003 /* Code indicating pure executable. */
/* There is no 64-bit QMAGIC as far as I know. */
#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
&& N_MAGIC(x) != NMAGIC \
&& N_MAGIC(x) != ZMAGIC)
#else
#define OMAGIC 0407 /* ...object file or impure executable. */
#define NMAGIC 0410 /* Code indicating pure executable. */
#define ZMAGIC 0413 /* Code indicating demand-paged executable. */
#define BMAGIC 0415 /* Used by a b.out object. */
/* This indicates a demand-paged executable with the header in the text.
It is used by 386BSD (and variants) and Linux, at least. */
#ifndef QMAGIC
#define QMAGIC 0314
#endif
# ifndef N_BADMAG
# define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
&& N_MAGIC(x) != NMAGIC \
&& N_MAGIC(x) != ZMAGIC \
&& N_MAGIC(x) != QMAGIC)
# endif /* N_BADMAG */
#endif
#endif
#ifdef QMAGIC
#define N_IS_QMAGIC(x) (N_MAGIC (x) == QMAGIC)
#else
#define N_IS_QMAGIC(x) (0)
#endif
/* The difference between TARGET_PAGE_SIZE and N_SEGSIZE is that TARGET_PAGE_SIZE is
the finest granularity at which you can page something, thus it
controls the padding (if any) before the text segment of a ZMAGIC
file. N_SEGSIZE is the resolution at which things can be marked as
read-only versus read/write, so it controls the padding between the
text segment and the data segment (in memory; on disk the padding
between them is TARGET_PAGE_SIZE). TARGET_PAGE_SIZE and N_SEGSIZE are the same
for most machines, but different for sun3. */
/* By default, segment size is constant. But some machines override this
to be a function of the a.out header (e.g. machine type). */
#ifndef N_SEGSIZE
#define N_SEGSIZE(x) SEGMENT_SIZE
#endif
/* Virtual memory address of the text section.
This is getting very complicated. A good reason to discard a.out format
for something that specifies these fields explicitly. But til then...
* OMAGIC and NMAGIC files:
(object files: text for "relocatable addr 0" right after the header)
start at 0, offset is EXEC_BYTES_SIZE, size as stated.
* The text address, offset, and size of ZMAGIC files depend
on the entry point of the file:
* entry point below TEXT_START_ADDR:
(hack for SunOS shared libraries)
start at 0, offset is 0, size as stated.
* If N_HEADER_IN_TEXT(x) is true (which defaults to being the
case when the entry point is EXEC_BYTES_SIZE or further into a page):
no padding is needed; text can start after exec header. Sun
considers the text segment of such files to include the exec header;
for BFD's purposes, we don't, which makes more work for us.
start at TEXT_START_ADDR + EXEC_BYTES_SIZE, offset is EXEC_BYTES_SIZE,
size as stated minus EXEC_BYTES_SIZE.
* If N_HEADER_IN_TEXT(x) is false (which defaults to being the case when
the entry point is less than EXEC_BYTES_SIZE into a page (e.g. page
aligned)): (padding is needed so that text can start at a page boundary)
start at TEXT_START_ADDR, offset TARGET_PAGE_SIZE, size as stated.
Specific configurations may want to hardwire N_HEADER_IN_TEXT,
for efficiency or to allow people to play games with the entry point.
In that case, you would #define N_HEADER_IN_TEXT(x) as 1 for sunos,
and as 0 for most other hosts (Sony News, Vax Ultrix, etc).
(Do this in the appropriate bfd target file.)
(The default is a heuristic that will break if people try changing
the entry point, perhaps with the ld -e flag.)
* QMAGIC is always like a ZMAGIC for which N_HEADER_IN_TEXT is true,
and for which the starting address is TARGET_PAGE_SIZE (or should this be
SEGMENT_SIZE?) (TEXT_START_ADDR only applies to ZMAGIC, not to QMAGIC).
*/
/* This macro is only relevant for ZMAGIC files; QMAGIC always has the header
in the text. */
#ifndef N_HEADER_IN_TEXT
#define N_HEADER_IN_TEXT(x) (((x).a_entry & (TARGET_PAGE_SIZE-1)) >= EXEC_BYTES_SIZE)
#endif
/* Sun shared libraries, not linux. This macro is only relevant for ZMAGIC
files. */
#ifndef N_SHARED_LIB
#define N_SHARED_LIB(x) ((x).a_entry < TEXT_START_ADDR)
#endif
/* Returning 0 not TEXT_START_ADDR for OMAGIC and NMAGIC is based on
the assumption that we are dealing with a .o file, not an
executable. This is necessary for OMAGIC (but means we don't work
right on the output from ld -N); more questionable for NMAGIC. */
#ifndef N_TXTADDR
#define N_TXTADDR(x) \
(/* The address of a QMAGIC file is always one page in, */ \
/* with the header in the text. */ \
N_IS_QMAGIC (x) ? TARGET_PAGE_SIZE + EXEC_BYTES_SIZE : \
N_MAGIC(x) != ZMAGIC ? 0 : /* object file or NMAGIC */\
N_SHARED_LIB(x) ? 0 : \
N_HEADER_IN_TEXT(x) ? \
TEXT_START_ADDR + EXEC_BYTES_SIZE : /* no padding */\
TEXT_START_ADDR /* a page of padding */\
)
#endif
/* If N_HEADER_IN_TEXT is not true for ZMAGIC, there is some padding
to make the text segment start at a certain boundary. For most
systems, this boundary is TARGET_PAGE_SIZE. But for Linux, in the
time-honored tradition of crazy ZMAGIC hacks, it is 1024 which is
not what TARGET_PAGE_SIZE needs to be for QMAGIC. */
#ifndef ZMAGIC_DISK_BLOCK_SIZE
#define ZMAGIC_DISK_BLOCK_SIZE TARGET_PAGE_SIZE
#endif
#define N_DISK_BLOCK_SIZE(x) \
(N_MAGIC(x) == ZMAGIC ? ZMAGIC_DISK_BLOCK_SIZE : TARGET_PAGE_SIZE)
/* Offset in an a.out of the start of the text section. */
#ifndef N_TXTOFF
#define N_TXTOFF(x) \
(/* For {O,N,Q}MAGIC, no padding. */ \
N_MAGIC(x) != ZMAGIC ? EXEC_BYTES_SIZE : \
N_SHARED_LIB(x) ? 0 : \
N_HEADER_IN_TEXT(x) ? \
EXEC_BYTES_SIZE : /* no padding */\
ZMAGIC_DISK_BLOCK_SIZE /* a page of padding */\
)
#endif
/* Size of the text section. It's always as stated, except that we
offset it to `undo' the adjustment to N_TXTADDR and N_TXTOFF
for ZMAGIC files that nominally include the exec header
as part of the first page of text. (BFD doesn't consider the
exec header to be part of the text segment.) */
#ifndef N_TXTSIZE
#define N_TXTSIZE(x) \
(/* For QMAGIC, we don't consider the header part of the text section. */\
N_IS_QMAGIC (x) ? (x).a_text - EXEC_BYTES_SIZE : \
(N_MAGIC(x) != ZMAGIC || N_SHARED_LIB(x)) ? (x).a_text : \
N_HEADER_IN_TEXT(x) ? \
(x).a_text - EXEC_BYTES_SIZE: /* no padding */\
(x).a_text /* a page of padding */\
)
#endif
/* The address of the data segment in virtual memory.
It is the text segment address, plus text segment size, rounded
up to a N_SEGSIZE boundary for pure or pageable files. */
#ifndef N_DATADDR
#define N_DATADDR(x) \
(N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+N_TXTSIZE(x)) \
: (N_SEGSIZE(x) + ((N_TXTADDR(x)+N_TXTSIZE(x)-1) & ~(N_SEGSIZE(x)-1))))
#endif
/* The address of the BSS segment -- immediately after the data segment. */
#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
/* Offsets of the various portions of the file after the text segment. */
/* For {Q,Z}MAGIC, there is padding to make the data segment start on
a page boundary. Most of the time the a_text field (and thus
N_TXTSIZE) already contains this padding. It is possible that for
BSDI and/or 386BSD it sometimes doesn't contain the padding, and
perhaps we should be adding it here. But this seems kind of
questionable and probably should be BSDI/386BSD-specific if we do
do it.
For NMAGIC (at least for hp300 BSD, probably others), there is
padding in memory only, not on disk, so we must *not* ever pad here
for NMAGIC. */
#ifndef N_DATOFF
#define N_DATOFF(x) \
(N_TXTOFF(x) + N_TXTSIZE(x))
#endif
#ifndef N_TRELOFF
#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data )
#endif
#ifndef N_DRELOFF
#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize )
#endif
#ifndef N_SYMOFF
#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize )
#endif
#ifndef N_STROFF
#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms )
#endif
/* Symbols */
#ifndef external_nlist
struct external_nlist {
bfd_byte e_strx[BYTES_IN_WORD]; /* index into string table of name */
bfd_byte e_type[1]; /* type of symbol */
bfd_byte e_other[1]; /* misc info (usually empty) */
bfd_byte e_desc[2]; /* description field */
bfd_byte e_value[BYTES_IN_WORD]; /* value of symbol */
};
#define EXTERNAL_NLIST_SIZE (BYTES_IN_WORD+4+BYTES_IN_WORD)
#endif
struct internal_nlist {
unsigned long n_strx; /* index into string table of name */
unsigned char n_type; /* type of symbol */
unsigned char n_other; /* misc info (usually empty) */
unsigned short n_desc; /* description field */
bfd_vma n_value; /* value of symbol */
};
/* The n_type field is the symbol type, containing: */
#define N_UNDF 0 /* Undefined symbol */
#define N_ABS 2 /* Absolute symbol -- defined at particular addr */
#define N_TEXT 4 /* Text sym -- defined at offset in text seg */
#define N_DATA 6 /* Data sym -- defined at offset in data seg */
#define N_BSS 8 /* BSS sym -- defined at offset in zero'd seg */
#define N_COMM 0x12 /* Common symbol (visible after shared lib dynlink) */
#define N_FN 0x1f /* File name of .o file */
#define N_FN_SEQ 0x0C /* N_FN from Sequent compilers (sigh) */
/* Note: N_EXT can only be usefully OR-ed with N_UNDF, N_ABS, N_TEXT,
N_DATA, or N_BSS. When the low-order bit of other types is set,
(e.g. N_WARNING versus N_FN), they are two different types. */
#define N_EXT 1 /* External symbol (as opposed to local-to-this-file) */
#define N_TYPE 0x1e
#define N_STAB 0xe0 /* If any of these bits are on, it's a debug symbol */
#define N_INDR 0x0a
/* The following symbols refer to set elements.
All the N_SET[ATDB] symbols with the same name form one set.
Space is allocated for the set in the text section, and each set
elements value is stored into one word of the space.
The first word of the space is the length of the set (number of elements).
The address of the set is made into an N_SETV symbol
whose name is the same as the name of the set.
This symbol acts like a N_DATA global symbol
in that it can satisfy undefined external references. */
/* These appear as input to LD, in a .o file. */
#define N_SETA 0x14 /* Absolute set element symbol */
#define N_SETT 0x16 /* Text set element symbol */
#define N_SETD 0x18 /* Data set element symbol */
#define N_SETB 0x1A /* Bss set element symbol */
/* This is output from LD. */
#define N_SETV 0x1C /* Pointer to set vector in data area. */
/* Warning symbol. The text gives a warning message, the next symbol
in the table will be undefined. When the symbol is referenced, the
message is printed. */
#define N_WARNING 0x1e
/* Weak symbols. These are a GNU extension to the a.out format. The
semantics are those of ELF weak symbols. Weak symbols are always
externally visible. The N_WEAK? values are squeezed into the
available slots. The value of a N_WEAKU symbol is 0. The values
of the other types are the definitions. */
#define N_WEAKU 0x0d /* Weak undefined symbol. */
#define N_WEAKA 0x0e /* Weak absolute symbol. */
#define N_WEAKT 0x0f /* Weak text symbol. */
#define N_WEAKD 0x10 /* Weak data symbol. */
#define N_WEAKB 0x11 /* Weak bss symbol. */
/* Relocations
There are two types of relocation flavours for a.out systems,
standard and extended. The standard form is used on systems where the
instruction has room for all the bits of an offset to the operand, whilst
the extended form is used when an address operand has to be split over n
instructions. Eg, on the 68k, each move instruction can reference
the target with a displacement of 16 or 32 bits. On the sparc, move
instructions use an offset of 14 bits, so the offset is stored in
the reloc field, and the data in the section is ignored.
*/
/* This structure describes a single relocation to be performed.
The text-relocation section of the file is a vector of these structures,
all of which apply to the text section.
Likewise, the data-relocation section applies to the data section. */
struct reloc_std_external {
bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */
bfd_byte r_index[3]; /* symbol table index of symbol */
bfd_byte r_type[1]; /* relocation type */
};
#define RELOC_STD_BITS_PCREL_BIG ((unsigned int) 0x80)
#define RELOC_STD_BITS_PCREL_LITTLE ((unsigned int) 0x01)
#define RELOC_STD_BITS_LENGTH_BIG ((unsigned int) 0x60)
#define RELOC_STD_BITS_LENGTH_SH_BIG 5
#define RELOC_STD_BITS_LENGTH_LITTLE ((unsigned int) 0x06)
#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1
#define RELOC_STD_BITS_EXTERN_BIG ((unsigned int) 0x10)
#define RELOC_STD_BITS_EXTERN_LITTLE ((unsigned int) 0x08)
#define RELOC_STD_BITS_BASEREL_BIG ((unsigned int) 0x08)
#define RELOC_STD_BITS_BASEREL_LITTLE ((unsigned int) 0x10)
#define RELOC_STD_BITS_JMPTABLE_BIG ((unsigned int) 0x04)
#define RELOC_STD_BITS_JMPTABLE_LITTLE ((unsigned int) 0x20)
#define RELOC_STD_BITS_RELATIVE_BIG ((unsigned int) 0x02)
#define RELOC_STD_BITS_RELATIVE_LITTLE ((unsigned int) 0x40)
#define RELOC_STD_SIZE (BYTES_IN_WORD + 3 + 1) /* Bytes per relocation entry */
struct reloc_std_internal
{
bfd_vma r_address; /* Address (within segment) to be relocated. */
/* The meaning of r_symbolnum depends on r_extern. */
unsigned int r_symbolnum:24;
/* Nonzero means value is a pc-relative offset
and it should be relocated for changes in its own address
as well as for changes in the symbol or section specified. */
unsigned int r_pcrel:1;
/* Length (as exponent of 2) of the field to be relocated.
Thus, a value of 2 indicates 1<<2 bytes. */
unsigned int r_length:2;
/* 1 => relocate with value of symbol.
r_symbolnum is the index of the symbol
in files the symbol table.
0 => relocate with the address of a segment.
r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
(the N_EXT bit may be set also, but signifies nothing). */
unsigned int r_extern:1;
/* The next three bits are for SunOS shared libraries, and seem to
be undocumented. */
unsigned int r_baserel:1; /* Linkage table relative */
unsigned int r_jmptable:1; /* pc-relative to jump table */
unsigned int r_relative:1; /* "relative relocation" */
/* unused */
unsigned int r_pad:1; /* Padding -- set to zero */
};
/* EXTENDED RELOCS */
struct reloc_ext_external {
bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */
bfd_byte r_index[3]; /* symbol table index of symbol */
bfd_byte r_type[1]; /* relocation type */
bfd_byte r_addend[BYTES_IN_WORD]; /* datum addend */
};
#define RELOC_EXT_BITS_EXTERN_BIG ((unsigned int) 0x80)
#define RELOC_EXT_BITS_EXTERN_LITTLE ((unsigned int) 0x01)
#define RELOC_EXT_BITS_TYPE_BIG ((unsigned int) 0x1F)
#define RELOC_EXT_BITS_TYPE_SH_BIG 0
#define RELOC_EXT_BITS_TYPE_LITTLE ((unsigned int) 0xF8)
#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3
/* Bytes per relocation entry */
#define RELOC_EXT_SIZE (BYTES_IN_WORD + 3 + 1 + BYTES_IN_WORD)
enum reloc_type
{
/* simple relocations */
RELOC_8, /* data[0:7] = addend + sv */
RELOC_16, /* data[0:15] = addend + sv */
RELOC_32, /* data[0:31] = addend + sv */
/* pc-rel displacement */
RELOC_DISP8, /* data[0:7] = addend - pc + sv */
RELOC_DISP16, /* data[0:15] = addend - pc + sv */
RELOC_DISP32, /* data[0:31] = addend - pc + sv */
/* Special */
RELOC_WDISP30, /* data[0:29] = (addend + sv - pc)>>2 */
RELOC_WDISP22, /* data[0:21] = (addend + sv - pc)>>2 */
RELOC_HI22, /* data[0:21] = (addend + sv)>>10 */
RELOC_22, /* data[0:21] = (addend + sv) */
RELOC_13, /* data[0:12] = (addend + sv) */
RELOC_LO10, /* data[0:9] = (addend + sv) */
RELOC_SFA_BASE,
RELOC_SFA_OFF13,
/* P.I.C. (base-relative) */
RELOC_BASE10, /* Not sure - maybe we can do this the */
RELOC_BASE13, /* right way now */
RELOC_BASE22,
/* for some sort of pc-rel P.I.C. (?) */
RELOC_PC10,
RELOC_PC22,
/* P.I.C. jump table */
RELOC_JMP_TBL,
/* reputedly for shared libraries somehow */
RELOC_SEGOFF16,
RELOC_GLOB_DAT,
RELOC_JMP_SLOT,
RELOC_RELATIVE,
RELOC_11,
RELOC_WDISP2_14,
RELOC_WDISP19,
RELOC_HHI22, /* data[0:21] = (addend + sv) >> 42 */
RELOC_HLO10, /* data[0:9] = (addend + sv) >> 32 */
/* 29K relocation types */
RELOC_JUMPTARG,
RELOC_CONST,
RELOC_CONSTH,
/* All the new ones I can think of, for sparc v9 */
RELOC_64, /* data[0:63] = addend + sv */
RELOC_DISP64, /* data[0:63] = addend - pc + sv */
RELOC_WDISP21, /* data[0:20] = (addend + sv - pc)>>2 */
RELOC_DISP21, /* data[0:20] = addend - pc + sv */
RELOC_DISP14, /* data[0:13] = addend - pc + sv */
/* Q .
What are the other ones,
Since this is a clean slate, can we throw away the ones we dont
understand ? Should we sort the values ? What about using a
microcode format like the 68k ?
*/
NO_RELOC
};
struct reloc_internal {
bfd_vma r_address; /* offset of of data to relocate */
long r_index; /* symbol table index of symbol */
enum reloc_type r_type; /* relocation type */
bfd_vma r_addend; /* datum addend */
};
/* Q.
Should the length of the string table be 4 bytes or 8 bytes ?
Q.
What about archive indexes ?
*/
#endif /* __A_OUT_64_H__ */

264
pstack/aout/stab.def Normal file
View File

@ -0,0 +1,264 @@
/* Table of DBX symbol codes for the GNU system.
Copyright (C) 1988, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* New stab from Solaris 2. This uses an n_type of 0, which in a.out files
overlaps the N_UNDF used for ordinary symbols. In ELF files, the
debug information is in a different file section, so there is no conflict.
This symbol's n_value gives the size of the string section associated
with this file. The symbol's n_strx (relative to the just-updated
string section start address) gives the name of the source file,
e.g. "foo.c", without any path information. The symbol's n_desc gives
the count of upcoming symbols associated with this file (not including
this one). */
/* __define_stab (N_UNDF, 0x00, "UNDF") */
/* Global variable. Only the name is significant.
To find the address, look in the corresponding external symbol. */
__define_stab (N_GSYM, 0x20, "GSYM")
/* Function name for BSD Fortran. Only the name is significant.
To find the address, look in the corresponding external symbol. */
__define_stab (N_FNAME, 0x22, "FNAME")
/* Function name or text-segment variable for C. Value is its address.
Desc is supposedly starting line number, but GCC doesn't set it
and DBX seems not to miss it. */
__define_stab (N_FUN, 0x24, "FUN")
/* Data-segment variable with internal linkage. Value is its address.
"Static Sym". */
__define_stab (N_STSYM, 0x26, "STSYM")
/* BSS-segment variable with internal linkage. Value is its address. */
__define_stab (N_LCSYM, 0x28, "LCSYM")
/* Name of main routine. Only the name is significant. */
__define_stab (N_MAIN, 0x2a, "MAIN")
/* Solaris2: Read-only data symbols. */
__define_stab (N_ROSYM, 0x2c, "ROSYM")
/* Global symbol in Pascal.
Supposedly the value is its line number; I'm skeptical. */
__define_stab (N_PC, 0x30, "PC")
/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */
__define_stab (N_NSYMS, 0x32, "NSYMS")
/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */
__define_stab (N_NOMAP, 0x34, "NOMAP")
/* New stab from Solaris 2. Like N_SO, but for the object file. Two in
a row provide the build directory and the relative path of the .o from it.
Solaris2 uses this to avoid putting the stabs info into the linked
executable; this stab goes into the ".stab.index" section, and the debugger
reads the real stabs directly from the .o files instead. */
__define_stab (N_OBJ, 0x38, "OBJ")
/* New stab from Solaris 2. Options for the debugger, related to the
source language for this module. E.g. whether to use ANSI
integral promotions or traditional integral promotions. */
__define_stab (N_OPT, 0x3c, "OPT")
/* Register variable. Value is number of register. */
__define_stab (N_RSYM, 0x40, "RSYM")
/* Modula-2 compilation unit. Can someone say what info it contains? */
__define_stab (N_M2C, 0x42, "M2C")
/* Line number in text segment. Desc is the line number;
value is corresponding address. On Solaris2, the line number is
relative to the start of the current function. */
__define_stab (N_SLINE, 0x44, "SLINE")
/* Similar, for data segment. */
__define_stab (N_DSLINE, 0x46, "DSLINE")
/* Similar, for bss segment. */
__define_stab (N_BSLINE, 0x48, "BSLINE")
/* Sun's source-code browser stabs. ?? Don't know what the fields are.
Supposedly the field is "path to associated .cb file". THIS VALUE
OVERLAPS WITH N_BSLINE! */
__define_stab_duplicate (N_BROWS, 0x48, "BROWS")
/* GNU Modula-2 definition module dependency. Value is the modification time
of the definition file. Other is non-zero if it is imported with the
GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there
are enough empty fields? */
__define_stab(N_DEFD, 0x4a, "DEFD")
/* New in Solaris2. Function start/body/end line numbers. */
__define_stab(N_FLINE, 0x4C, "FLINE")
/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2
and one is for C++. Still,... */
/* GNU C++ exception variable. Name is variable name. */
__define_stab (N_EHDECL, 0x50, "EHDECL")
/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */
__define_stab_duplicate (N_MOD2, 0x50, "MOD2")
/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if
this entry is immediately followed by a CAUGHT stab saying what exception
was caught. Multiple CAUGHT stabs means that multiple exceptions
can be caught here. If Desc is 0, it means all exceptions are caught
here. */
__define_stab (N_CATCH, 0x54, "CATCH")
/* Structure or union element. Value is offset in the structure. */
__define_stab (N_SSYM, 0x60, "SSYM")
/* Solaris2: Last stab emitted for module. */
__define_stab (N_ENDM, 0x62, "ENDM")
/* Name of main source file.
Value is starting text address of the compilation.
If multiple N_SO's appear, the first to contain a trailing / is the
compilation directory. The first to not contain a trailing / is the
source file name, relative to the compilation directory. Others (perhaps
resulting from cfront) are ignored.
On Solaris2, value is undefined, but desc is a source-language code. */
__define_stab (N_SO, 0x64, "SO")
/* Automatic variable in the stack. Value is offset from frame pointer.
Also used for type descriptions. */
__define_stab (N_LSYM, 0x80, "LSYM")
/* Beginning of an include file. Only Sun uses this.
In an object file, only the name is significant.
The Sun linker puts data into some of the other fields. */
__define_stab (N_BINCL, 0x82, "BINCL")
/* Name of sub-source file (#include file).
Value is starting text address of the compilation. */
__define_stab (N_SOL, 0x84, "SOL")
/* Parameter variable. Value is offset from argument pointer.
(On most machines the argument pointer is the same as the frame pointer. */
__define_stab (N_PSYM, 0xa0, "PSYM")
/* End of an include file. No name.
This and N_BINCL act as brackets around the file's output.
In an object file, there is no significant data in this entry.
The Sun linker puts data into some of the fields. */
__define_stab (N_EINCL, 0xa2, "EINCL")
/* Alternate entry point. Value is its address. */
__define_stab (N_ENTRY, 0xa4, "ENTRY")
/* Beginning of lexical block.
The desc is the nesting level in lexical blocks.
The value is the address of the start of the text for the block.
The variables declared inside the block *precede* the N_LBRAC symbol.
On Solaris2, the value is relative to the start of the current function. */
__define_stab (N_LBRAC, 0xc0, "LBRAC")
/* Place holder for deleted include file. Replaces a N_BINCL and everything
up to the corresponding N_EINCL. The Sun linker generates these when
it finds multiple identical copies of the symbols from an include file.
This appears only in output from the Sun linker. */
__define_stab (N_EXCL, 0xc2, "EXCL")
/* Modula-2 scope information. Can someone say what info it contains? */
__define_stab (N_SCOPE, 0xc4, "SCOPE")
/* End of a lexical block. Desc matches the N_LBRAC's desc.
The value is the address of the end of the text for the block.
On Solaris2, the value is relative to the start of the current function. */
__define_stab (N_RBRAC, 0xe0, "RBRAC")
/* Begin named common block. Only the name is significant. */
__define_stab (N_BCOMM, 0xe2, "BCOMM")
/* End named common block. Only the name is significant
(and it should match the N_BCOMM). */
__define_stab (N_ECOMM, 0xe4, "ECOMM")
/* Member of a common block; value is offset within the common block.
This should occur within a BCOMM/ECOMM pair. */
__define_stab (N_ECOML, 0xe8, "ECOML")
/* Solaris2: Pascal "with" statement: type,,0,0,offset */
__define_stab (N_WITH, 0xea, "WITH")
/* These STAB's are used on Gould systems for Non-Base register symbols
or something like that. FIXME. I have assigned the values at random
since I don't have a Gould here. Fixups from Gould folk welcome... */
__define_stab (N_NBTEXT, 0xF0, "NBTEXT")
__define_stab (N_NBDATA, 0xF2, "NBDATA")
__define_stab (N_NBBSS, 0xF4, "NBBSS")
__define_stab (N_NBSTS, 0xF6, "NBSTS")
__define_stab (N_NBLCS, 0xF8, "NBLCS")
/* Second symbol entry containing a length-value for the preceding entry.
The value is the length. */
__define_stab (N_LENG, 0xfe, "LENG")
/* The above information, in matrix format.
STAB MATRIX
_________________________________________________
| 00 - 1F are not dbx stab symbols |
| In most cases, the low bit is the EXTernal bit|
| 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA |
| 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT |
| 08 BSS | 0A INDR | 0C FN_SEQ | 0E WEAKA |
| 09 |EXT | 0B | 0D WEAKU | 0F WEAKT |
| 10 WEAKD | 12 COMM | 14 SETA | 16 SETT |
| 11 WEAKB | 13 | 15 | 17 |
| 18 SETD | 1A SETB | 1C SETV | 1E WARNING|
| 19 | 1B | 1D | 1F FN |
|_______________________________________________|
| Debug entries with bit 01 set are unused. |
| 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM |
| 28 LCSYM | 2A MAIN | 2C ROSYM | 2E |
| 30 PC | 32 NSYMS | 34 NOMAP | 36 |
| 38 OBJ | 3A | 3C OPT | 3E |
| 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE |
| 48 BSLINE*| 4A DEFD | 4C FLINE | 4E |
| 50 EHDECL*| 52 | 54 CATCH | 56 |
| 58 | 5A | 5C | 5E |
| 60 SSYM | 62 ENDM | 64 SO | 66 |
| 68 | 6A | 6C | 6E |
| 70 | 72 | 74 | 76 |
| 78 | 7A | 7C | 7E |
| 80 LSYM | 82 BINCL | 84 SOL | 86 |
| 88 | 8A | 8C | 8E |
| 90 | 92 | 94 | 96 |
| 98 | 9A | 9C | 9E |
| A0 PSYM | A2 EINCL | A4 ENTRY | A6 |
| A8 | AA | AC | AE |
| B0 | B2 | B4 | B6 |
| B8 | BA | BC | BE |
| C0 LBRAC | C2 EXCL | C4 SCOPE | C6 |
| C8 | CA | CC | CE |
| D0 | D2 | D4 | D6 |
| D8 | DA | DC | DE |
| E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 |
| E8 ECOML | EA WITH | EC | EE |
| F0 | F2 | F4 | F6 |
| F8 | FA | FC | FE LENG |
+-----------------------------------------------+
* 50 EHDECL is also MOD2.
* 48 BSLINE is also BROWS.
*/

37
pstack/aout/stab_gnu.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef __GNU_STAB__
/* Indicate the GNU stab.h is in use. */
#define __GNU_STAB__
#define __define_stab(NAME, CODE, STRING) NAME=CODE,
#define __define_stab_duplicate(NAME, CODE, STRING) NAME=CODE,
enum __stab_debug_code
{
#include "aout/stab.def"
LAST_UNUSED_STAB_CODE
};
#undef __define_stab
/* Definitions of "desc" field for N_SO stabs in Solaris2. */
#define N_SO_AS 1
#define N_SO_C 2
#define N_SO_ANSI_C 3
#define N_SO_CC 4 /* C++ */
#define N_SO_FORTRAN 5
#define N_SO_PASCAL 6
/* Solaris2: Floating point type values in basic types. */
#define NF_NONE 0
#define NF_SINGLE 1 /* IEEE 32-bit */
#define NF_DOUBLE 2 /* IEEE 64-bit */
#define NF_COMPLEX 3 /* Fortran complex */
#define NF_COMPLEX16 4 /* Fortran double complex */
#define NF_COMPLEX32 5 /* Fortran complex*16 */
#define NF_LDOUBLE 6 /* Long double (whatever that is) */
#endif /* __GNU_STAB_ */

238
pstack/bucomm.c Normal file
View File

@ -0,0 +1,238 @@
/* bucomm.c -- Bin Utils COMmon code.
Copyright (C) 1991, 92, 93, 94, 95, 1997 Free Software Foundation, Inc.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* We might put this in a library someday so it could be dynamically
loaded, but for now it's not necessary. */
#include <bfd.h>
#include <libiberty.h>
#include "bucomm.h"
#include <sys/stat.h>
#include <time.h> /* ctime, maybe time_t */
#ifdef ANSI_PROTOTYPES
#include <stdarg.h>
#else
#include <varargs.h>
#endif
/* Error reporting */
char *program_name;
void
bfd_nonfatal (string)
CONST char *string;
{
CONST char *errmsg = bfd_errmsg (bfd_get_error ());
if (string)
fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
else
fprintf (stderr, "%s: %s\n", program_name, errmsg);
}
void
bfd_fatal (string)
CONST char *string;
{
bfd_nonfatal (string);
xexit (1);
}
#ifdef ANSI_PROTOTYPES
void
fatal (const char *format, ...)
{
va_list args;
fprintf (stderr, "%s: ", program_name);
va_start (args, format);
vfprintf (stderr, format, args);
va_end (args);
putc ('\n', stderr);
xexit (1);
}
#else
void
fatal (va_alist)
va_dcl
{
char *Format;
va_list args;
fprintf (stderr, "%s: ", program_name);
va_start (args);
Format = va_arg (args, char *);
vfprintf (stderr, Format, args);
va_end (args);
putc ('\n', stderr);
xexit (1);
}
#endif
/* Set the default BFD target based on the configured target. Doing
this permits the binutils to be configured for a particular target,
and linked against a shared BFD library which was configured for a
different target. */
#define TARGET "elf32-i386" /* FIXME: hard-coded! */
void
set_default_bfd_target ()
{
/* The macro TARGET is defined by Makefile. */
const char *target = TARGET;
if (! bfd_set_default_target (target))
{
char *errmsg;
errmsg = (char *) xmalloc (100 + strlen (target));
sprintf (errmsg, "can't set BFD default target to `%s'", target);
bfd_fatal (errmsg);
}
}
/* After a false return from bfd_check_format_matches with
bfd_get_error () == bfd_error_file_ambiguously_recognized, print
the possible matching targets. */
void
list_matching_formats (p)
char **p;
{
fprintf(stderr, "%s: Matching formats:", program_name);
while (*p)
fprintf(stderr, " %s", *p++);
fprintf(stderr, "\n");
}
/* List the supported targets. */
void
list_supported_targets (name, f)
const char *name;
FILE *f;
{
extern bfd_target *bfd_target_vector[];
int t;
if (name == NULL)
fprintf (f, "Supported targets:");
else
fprintf (f, "%s: supported targets:", name);
for (t = 0; bfd_target_vector[t] != NULL; t++)
fprintf (f, " %s", bfd_target_vector[t]->name);
fprintf (f, "\n");
}
/* Display the archive header for an element as if it were an ls -l listing:
Mode User\tGroup\tSize\tDate Name */
void
print_arelt_descr (file, abfd, verbose)
FILE *file;
bfd *abfd;
boolean verbose;
{
struct stat buf;
if (verbose)
{
if (bfd_stat_arch_elt (abfd, &buf) == 0)
{
char modebuf[11];
char timebuf[40];
time_t when = buf.st_mtime;
CONST char *ctime_result = (CONST char *) ctime (&when);
/* POSIX format: skip weekday and seconds from ctime output. */
sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
mode_string (buf.st_mode, modebuf);
modebuf[10] = '\0';
/* POSIX 1003.2/D11 says to skip first character (entry type). */
fprintf (file, "%s %ld/%ld %6ld %s ", modebuf + 1,
(long) buf.st_uid, (long) buf.st_gid,
(long) buf.st_size, timebuf);
}
}
fprintf (file, "%s\n", bfd_get_filename (abfd));
}
/* Return the name of a temporary file in the same directory as FILENAME. */
char *
make_tempname (filename)
char *filename;
{
static char template[] = "stXXXXXX";
char *tmpname;
char *slash = strrchr (filename, '/');
#if defined (__DJGPP__) || defined (__GO32__) || defined (_WIN32)
if (slash == NULL)
slash = strrchr (filename, '\\');
#endif
if (slash != (char *) NULL)
{
char c;
c = *slash;
*slash = 0;
tmpname = xmalloc (strlen (filename) + sizeof (template) + 1);
strcpy (tmpname, filename);
strcat (tmpname, "/");
strcat (tmpname, template);
mktemp (tmpname);
*slash = c;
}
else
{
tmpname = xmalloc (sizeof (template));
strcpy (tmpname, template);
mktemp (tmpname);
}
return tmpname;
}
/* Parse a string into a VMA, with a fatal error if it can't be
parsed. */
bfd_vma
parse_vma (s, arg)
const char *s;
const char *arg;
{
bfd_vma ret;
const char *end;
ret = bfd_scan_vma (s, &end, 0);
if (*end != '\0')
{
fprintf (stderr, "%s: %s: bad number: %s\n", program_name, arg, s);
exit (1);
}
return ret;
}

85
pstack/bucomm.h Normal file
View File

@ -0,0 +1,85 @@
/* bucomm.h -- binutils common include file.
Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef _BUCOMM_H
#define _BUCOMM_H
#include "ansidecl.h"
#include <stdio.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#ifdef __GNUC__
# undef alloca
# define alloca __builtin_alloca
#else
# if HAVE_ALLOCA_H
# include <alloca.h>
# else
# ifndef alloca /* predefined by HP cc +Olibcalls */
# if !defined (__STDC__) && !defined (__hpux)
char *alloca ();
# else
void *alloca ();
# endif /* __STDC__, __hpux */
# endif /* alloca */
# endif /* HAVE_ALLOCA_H */
#endif
/* bucomm.c */
void bfd_nonfatal PARAMS ((CONST char *));
void bfd_fatal PARAMS ((CONST char *));
void fatal PARAMS ((CONST char *, ...));
void set_default_bfd_target PARAMS ((void));
void list_matching_formats PARAMS ((char **p));
void list_supported_targets PARAMS ((const char *, FILE *));
void print_arelt_descr PARAMS ((FILE *file, bfd *abfd, boolean verbose));
char *make_tempname PARAMS ((char *));
bfd_vma parse_vma PARAMS ((const char *, const char *));
extern char *program_name;
/* filemode.c */
void mode_string PARAMS ((unsigned long mode, char *buf));
/* version.c */
extern void print_version PARAMS ((const char *));
/* libiberty */
PTR xmalloc PARAMS ((size_t));
PTR xrealloc PARAMS ((PTR, size_t));
#endif /* _BUCOMM_H */

58
pstack/budbg.h Normal file
View File

@ -0,0 +1,58 @@
/* budbg.c -- Interfaces to the generic debugging information routines.
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#ifndef BUDBG_H
#define BUDBG_H
#include <stdio.h>
/* Routine used to read generic debugging information. */
extern PTR read_debugging_info PARAMS ((bfd *, asymbol **, long));
/* Routine used to print generic debugging information. */
extern boolean print_debugging_info PARAMS ((FILE *, PTR));
/* Routines used to read and write stabs information. */
extern PTR start_stab PARAMS ((PTR, bfd *, boolean, asymbol **, long));
extern boolean finish_stab PARAMS ((PTR, PTR));
extern boolean parse_stab PARAMS ((PTR, PTR, int, int, bfd_vma, const char *));
extern boolean write_stabs_in_sections_debugging_info
PARAMS ((bfd *, PTR, bfd_byte **, bfd_size_type *, bfd_byte **,
bfd_size_type *));
/* Routines used to read and write IEEE debugging information. */
extern boolean parse_ieee
PARAMS ((PTR, bfd *, const bfd_byte *, bfd_size_type));
extern boolean write_ieee_debugging_info PARAMS ((bfd *, PTR));
/* Routine used to read COFF debugging information. */
extern boolean parse_coff PARAMS ((bfd *, asymbol **, long, PTR));
#endif

3509
pstack/debug.c Normal file

File diff suppressed because it is too large Load Diff

798
pstack/debug.h Normal file
View File

@ -0,0 +1,798 @@
/* debug.h -- Describe generic debugging information.
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#ifndef DEBUG_H
#define DEBUG_H
/* This header file describes a generic debugging information format.
We may eventually have readers which convert different formats into
this generic format, and writers which write it out. The initial
impetus for this was writing a convertor from stabs to HP IEEE-695
debugging format. */
/* Different kinds of types. */
enum debug_type_kind
{
/* Not used. */
DEBUG_KIND_ILLEGAL,
/* Indirect via a pointer. */
DEBUG_KIND_INDIRECT,
/* Void. */
DEBUG_KIND_VOID,
/* Integer. */
DEBUG_KIND_INT,
/* Floating point. */
DEBUG_KIND_FLOAT,
/* Complex. */
DEBUG_KIND_COMPLEX,
/* Boolean. */
DEBUG_KIND_BOOL,
/* Struct. */
DEBUG_KIND_STRUCT,
/* Union. */
DEBUG_KIND_UNION,
/* Class. */
DEBUG_KIND_CLASS,
/* Union class (can this really happen?). */
DEBUG_KIND_UNION_CLASS,
/* Enumeration type. */
DEBUG_KIND_ENUM,
/* Pointer. */
DEBUG_KIND_POINTER,
/* Function. */
DEBUG_KIND_FUNCTION,
/* Reference. */
DEBUG_KIND_REFERENCE,
/* Range. */
DEBUG_KIND_RANGE,
/* Array. */
DEBUG_KIND_ARRAY,
/* Set. */
DEBUG_KIND_SET,
/* Based pointer. */
DEBUG_KIND_OFFSET,
/* Method. */
DEBUG_KIND_METHOD,
/* Const qualified type. */
DEBUG_KIND_CONST,
/* Volatile qualified type. */
DEBUG_KIND_VOLATILE,
/* Named type. */
DEBUG_KIND_NAMED,
/* Tagged type. */
DEBUG_KIND_TAGGED
};
/* Different kinds of variables. */
enum debug_var_kind
{
/* Not used. */
DEBUG_VAR_ILLEGAL,
/* A global variable. */
DEBUG_GLOBAL,
/* A static variable. */
DEBUG_STATIC,
/* A local static variable. */
DEBUG_LOCAL_STATIC,
/* A local variable. */
DEBUG_LOCAL,
/* A register variable. */
DEBUG_REGISTER
};
/* Different kinds of function parameters. */
enum debug_parm_kind
{
/* Not used. */
DEBUG_PARM_ILLEGAL,
/* A stack based parameter. */
DEBUG_PARM_STACK,
/* A register parameter. */
DEBUG_PARM_REG,
/* A stack based reference parameter. */
DEBUG_PARM_REFERENCE,
/* A register reference parameter. */
DEBUG_PARM_REF_REG
};
/* Different kinds of visibility. */
enum debug_visibility
{
/* A public field (e.g., a field in a C struct). */
DEBUG_VISIBILITY_PUBLIC,
/* A protected field. */
DEBUG_VISIBILITY_PROTECTED,
/* A private field. */
DEBUG_VISIBILITY_PRIVATE,
/* A field which should be ignored. */
DEBUG_VISIBILITY_IGNORE
};
/* A type. */
typedef struct debug_type *debug_type;
#define DEBUG_TYPE_NULL ((debug_type) NULL)
/* A field in a struct or union. */
typedef struct debug_field *debug_field;
#define DEBUG_FIELD_NULL ((debug_field) NULL)
/* A base class for an object. */
typedef struct debug_baseclass *debug_baseclass;
#define DEBUG_BASECLASS_NULL ((debug_baseclass) NULL)
/* A method of an object. */
typedef struct debug_method *debug_method;
#define DEBUG_METHOD_NULL ((debug_method) NULL)
/* The arguments to a method function of an object. These indicate
which method to run. */
typedef struct debug_method_variant *debug_method_variant;
#define DEBUG_METHOD_VARIANT_NULL ((debug_method_variant) NULL)
/* This structure is passed to debug_write. It holds function
pointers that debug_write will call based on the accumulated
debugging information. */
struct debug_write_fns
{
/* This is called at the start of each new compilation unit with the
name of the main file in the new unit. */
boolean (*start_compilation_unit) PARAMS ((PTR, const char *));
/* This is called at the start of each source file within a
compilation unit, before outputting any global information for
that file. The argument is the name of the file. */
boolean (*start_source) PARAMS ((PTR, const char *));
/* Each writer must keep a stack of types. */
/* Push an empty type onto the type stack. This type can appear if
there is a reference to a type which is never defined. */
boolean (*empty_type) PARAMS ((PTR));
/* Push a void type onto the type stack. */
boolean (*void_type) PARAMS ((PTR));
/* Push an integer type onto the type stack, given the size and
whether it is unsigned. */
boolean (*int_type) PARAMS ((PTR, unsigned int, boolean));
/* Push a floating type onto the type stack, given the size. */
boolean (*float_type) PARAMS ((PTR, unsigned int));
/* Push a complex type onto the type stack, given the size. */
boolean (*complex_type) PARAMS ((PTR, unsigned int));
/* Push a boolean type onto the type stack, given the size. */
boolean (*bool_type) PARAMS ((PTR, unsigned int));
/* Push an enum type onto the type stack, given the tag, a NULL
terminated array of names and the associated values. If there is
no tag, the tag argument will be NULL. If this is an undefined
enum, the names and values arguments will be NULL. */
boolean (*enum_type) PARAMS ((PTR, const char *, const char **,
bfd_signed_vma *));
/* Pop the top type on the type stack, and push a pointer to that
type onto the type stack. */
boolean (*pointer_type) PARAMS ((PTR));
/* Push a function type onto the type stack. The second argument
indicates the number of argument types that have been pushed onto
the stack. If the number of argument types is passed as -1, then
the argument types of the function are unknown, and no types have
been pushed onto the stack. The third argument is true if the
function takes a variable number of arguments. The return type
of the function is pushed onto the type stack below the argument
types, if any. */
boolean (*function_type) PARAMS ((PTR, int, boolean));
/* Pop the top type on the type stack, and push a reference to that
type onto the type stack. */
boolean (*reference_type) PARAMS ((PTR));
/* Pop the top type on the type stack, and push a range of that type
with the given lower and upper bounds onto the type stack. */
boolean (*range_type) PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma));
/* Push an array type onto the type stack. The top type on the type
stack is the range, and the next type on the type stack is the
element type. These should be popped before the array type is
pushed. The arguments are the lower bound, the upper bound, and
whether the array is a string. */
boolean (*array_type) PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma,
boolean));
/* Pop the top type on the type stack, and push a set of that type
onto the type stack. The argument indicates whether this set is
a bitstring. */
boolean (*set_type) PARAMS ((PTR, boolean));
/* Push an offset type onto the type stack. The top type on the
type stack is the target type, and the next type on the type
stack is the base type. These should be popped before the offset
type is pushed. */
boolean (*offset_type) PARAMS ((PTR));
/* Push a method type onto the type stack. If the second argument
is true, the top type on the stack is the class to which the
method belongs; otherwise, the class must be determined by the
class to which the method is attached. The third argument is the
number of argument types; these are pushed onto the type stack in
reverse order (the first type popped is the last argument to the
method). A value of -1 for the third argument means that no
argument information is available. The fourth argument is true
if the function takes a variable number of arguments. The next
type on the type stack below the domain and the argument types is
the return type of the method. All these types must be popped,
and then the method type must be pushed. */
boolean (*method_type) PARAMS ((PTR, boolean, int, boolean));
/* Pop the top type off the type stack, and push a const qualified
version of that type onto the type stack. */
boolean (*const_type) PARAMS ((PTR));
/* Pop the top type off the type stack, and push a volatile
qualified version of that type onto the type stack. */
boolean (*volatile_type) PARAMS ((PTR));
/* Start building a struct. This is followed by calls to the
struct_field function, and finished by a call to the
end_struct_type function. The second argument is the tag; this
will be NULL if there isn't one. If the second argument is NULL,
the third argument is a constant identifying this struct for use
with tag_type. The fourth argument is true for a struct, false
for a union. The fifth argument is the size. If this is an
undefined struct or union, the size will be 0 and struct_field
will not be called before end_struct_type is called. */
boolean (*start_struct_type) PARAMS ((PTR, const char *, unsigned int,
boolean, unsigned int));
/* Add a field to the struct type currently being built. The type
of the field should be popped off the type stack. The arguments
are the name, the bit position, the bit size (may be zero if the
field is not packed), and the visibility. */
boolean (*struct_field) PARAMS ((PTR, const char *, bfd_vma, bfd_vma,
enum debug_visibility));
/* Finish building a struct, and push it onto the type stack. */
boolean (*end_struct_type) PARAMS ((PTR));
/* Start building a class. This is followed by calls to several
functions: struct_field, class_static_member, class_baseclass,
class_start_method, class_method_variant,
class_static_method_variant, and class_end_method. The class is
finished by a call to end_class_type. The first five arguments
are the same as for start_struct_type. The sixth argument is
true if there is a virtual function table; if there is, the
seventh argument is true if the virtual function table can be
found in the type itself, and is false if the type of the object
holding the virtual function table should be popped from the type
stack. */
boolean (*start_class_type) PARAMS ((PTR, const char *, unsigned int,
boolean, unsigned int, boolean,
boolean));
/* Add a static member to the class currently being built. The
arguments are the field name, the physical name, and the
visibility. The type must be popped off the type stack. */
boolean (*class_static_member) PARAMS ((PTR, const char *, const char *,
enum debug_visibility));
/* Add a baseclass to the class currently being built. The type of
the baseclass must be popped off the type stack. The arguments
are the bit position, whether the class is virtual, and the
visibility. */
boolean (*class_baseclass) PARAMS ((PTR, bfd_vma, boolean,
enum debug_visibility));
/* Start adding a method to the class currently being built. This
is followed by calls to class_method_variant and
class_static_method_variant to describe different variants of the
method which take different arguments. The method is finished
with a call to class_end_method. The argument is the method
name. */
boolean (*class_start_method) PARAMS ((PTR, const char *));
/* Describe a variant to the class method currently being built.
The type of the variant must be popped off the type stack. The
second argument is the physical name of the function. The
following arguments are the visibility, whether the variant is
const, whether the variant is volatile, the offset in the virtual
function table, and whether the context is on the type stack
(below the variant type). */
boolean (*class_method_variant) PARAMS ((PTR, const char *,
enum debug_visibility,
boolean, boolean,
bfd_vma, boolean));
/* Describe a static variant to the class method currently being
built. The arguments are the same as for class_method_variant,
except that the last two arguments are omitted. The type of the
variant must be popped off the type stack. */
boolean (*class_static_method_variant) PARAMS ((PTR, const char *,
enum debug_visibility,
boolean, boolean));
/* Finish describing a class method. */
boolean (*class_end_method) PARAMS ((PTR));
/* Finish describing a class, and push it onto the type stack. */
boolean (*end_class_type) PARAMS ((PTR));
/* Push a type on the stack which was given a name by an earlier
call to typdef. */
boolean (*typedef_type) PARAMS ((PTR, const char *));
/* Push a tagged type on the stack which was defined earlier. If
the second argument is not NULL, the type was defined by a call
to tag. If the second argument is NULL, the type was defined by
a call to start_struct_type or start_class_type with a tag of
NULL and the number of the third argument. Either way, the
fourth argument is the tag kind. Note that this may be called
for a struct (class) being defined, in between the call to
start_struct_type (start_class_type) and the call to
end_struct_type (end_class_type). */
boolean (*tag_type) PARAMS ((PTR, const char *, unsigned int,
enum debug_type_kind));
/* Pop the type stack, and typedef it to the given name. */
boolean (*typdef) PARAMS ((PTR, const char *));
/* Pop the type stack, and declare it as a tagged struct or union or
enum or whatever. The tag passed down here is redundant, since
was also passed when enum_type, start_struct_type, or
start_class_type was called. */
boolean (*tag) PARAMS ((PTR, const char *));
/* This is called to record a named integer constant. */
boolean (*int_constant) PARAMS ((PTR, const char *, bfd_vma));
/* This is called to record a named floating point constant. */
boolean (*float_constant) PARAMS ((PTR, const char *, double));
/* This is called to record a typed integer constant. The type is
popped off the type stack. */
boolean (*typed_constant) PARAMS ((PTR, const char *, bfd_vma));
/* This is called to record a variable. The type is popped off the
type stack. */
boolean (*variable) PARAMS ((PTR, const char *, enum debug_var_kind,
bfd_vma));
/* Start writing out a function. The return type must be popped off
the stack. The boolean is true if the function is global. This
is followed by calls to function_parameter, followed by block
information. */
boolean (*start_function) PARAMS ((PTR, const char *, boolean));
/* Record a function parameter for the current function. The type
must be popped off the stack. */
boolean (*function_parameter) PARAMS ((PTR, const char *,
enum debug_parm_kind, bfd_vma));
/* Start writing out a block. There is at least one top level block
per function. Blocks may be nested. The argument is the
starting address of the block. */
boolean (*start_block) PARAMS ((PTR, bfd_vma));
/* Finish writing out a block. The argument is the ending address
of the block. */
boolean (*end_block) PARAMS ((PTR, bfd_vma));
/* Finish writing out a function. */
boolean (*end_function) PARAMS ((PTR));
/* Record line number information for the current compilation unit. */
boolean (*lineno) PARAMS ((PTR, const char *, unsigned long, bfd_vma));
};
/* Exported functions. */
/* The first argument to most of these functions is a handle. This
handle is returned by the debug_init function. The purpose of the
handle is to permit the debugging routines to not use static
variables, and hence to be reentrant. This would be useful for a
program which wanted to handle two executables simultaneously. */
/* Return a debugging handle. */
extern PTR debug_init PARAMS ((void));
/* Set the source filename. This implicitly starts a new compilation
unit. */
extern boolean debug_set_filename PARAMS ((PTR, const char *));
/* Change source files to the given file name. This is used for
include files in a single compilation unit. */
extern boolean debug_start_source PARAMS ((PTR, const char *));
/* Record a function definition. This implicitly starts a function
block. The debug_type argument is the type of the return value.
The boolean indicates whether the function is globally visible.
The bfd_vma is the address of the start of the function. Currently
the parameter types are specified by calls to
debug_record_parameter. */
extern boolean debug_record_function
PARAMS ((PTR, const char *, debug_type, boolean, bfd_vma));
/* Record a parameter for the current function. */
extern boolean debug_record_parameter
PARAMS ((PTR, const char *, debug_type, enum debug_parm_kind, bfd_vma));
/* End a function definition. The argument is the address where the
function ends. */
extern boolean debug_end_function PARAMS ((PTR, bfd_vma));
/* Start a block in a function. All local information will be
recorded in this block, until the matching call to debug_end_block.
debug_start_block and debug_end_block may be nested. The argument
is the address at which this block starts. */
extern boolean debug_start_block PARAMS ((PTR, bfd_vma));
/* Finish a block in a function. This matches the call to
debug_start_block. The argument is the address at which this block
ends. */
extern boolean debug_end_block PARAMS ((PTR, bfd_vma));
/* Associate a line number in the current source file with a given
address. */
extern boolean debug_record_line PARAMS ((PTR, unsigned long, bfd_vma));
/* Start a named common block. This is a block of variables that may
move in memory. */
extern boolean debug_start_common_block PARAMS ((PTR, const char *));
/* End a named common block. */
extern boolean debug_end_common_block PARAMS ((PTR, const char *));
/* Record a named integer constant. */
extern boolean debug_record_int_const PARAMS ((PTR, const char *, bfd_vma));
/* Record a named floating point constant. */
extern boolean debug_record_float_const PARAMS ((PTR, const char *, double));
/* Record a typed constant with an integral value. */
extern boolean debug_record_typed_const
PARAMS ((PTR, const char *, debug_type, bfd_vma));
/* Record a label. */
extern boolean debug_record_label
PARAMS ((PTR, const char *, debug_type, bfd_vma));
/* Record a variable. */
extern boolean debug_record_variable
PARAMS ((PTR, const char *, debug_type, enum debug_var_kind, bfd_vma));
/* Make an indirect type. The first argument is a pointer to the
location where the real type will be placed. The second argument
is the type tag, if there is one; this may be NULL; the only
purpose of this argument is so that debug_get_type_name can return
something useful. This function may be used when a type is
referenced before it is defined. */
extern debug_type debug_make_indirect_type
PARAMS ((PTR, debug_type *, const char *));
/* Make a void type. */
extern debug_type debug_make_void_type PARAMS ((PTR));
/* Make an integer type of a given size. The boolean argument is true
if the integer is unsigned. */
extern debug_type debug_make_int_type PARAMS ((PTR, unsigned int, boolean));
/* Make a floating point type of a given size. FIXME: On some
platforms, like an Alpha, you probably need to be able to specify
the format. */
extern debug_type debug_make_float_type PARAMS ((PTR, unsigned int));
/* Make a boolean type of a given size. */
extern debug_type debug_make_bool_type PARAMS ((PTR, unsigned int));
/* Make a complex type of a given size. */
extern debug_type debug_make_complex_type PARAMS ((PTR, unsigned int));
/* Make a structure type. The second argument is true for a struct,
false for a union. The third argument is the size of the struct.
The fourth argument is a NULL terminated array of fields. */
extern debug_type debug_make_struct_type
PARAMS ((PTR, boolean, bfd_vma, debug_field *));
/* Make an object type. The first three arguments after the handle
are the same as for debug_make_struct_type. The next arguments are
a NULL terminated array of base classes, a NULL terminated array of
methods, the type of the object holding the virtual function table
if it is not this object, and a boolean which is true if this
object has its own virtual function table. */
extern debug_type debug_make_object_type
PARAMS ((PTR, boolean, bfd_vma, debug_field *, debug_baseclass *,
debug_method *, debug_type, boolean));
/* Make an enumeration type. The arguments are a null terminated
array of strings, and an array of corresponding values. */
extern debug_type debug_make_enum_type
PARAMS ((PTR, const char **, bfd_signed_vma *));
/* Make a pointer to a given type. */
extern debug_type debug_make_pointer_type
PARAMS ((PTR, debug_type));
/* Make a function type. The second argument is the return type. The
third argument is a NULL terminated array of argument types. The
fourth argument is true if the function takes a variable number of
arguments. If the third argument is NULL, then the argument types
are unknown. */
extern debug_type debug_make_function_type
PARAMS ((PTR, debug_type, debug_type *, boolean));
/* Make a reference to a given type. */
extern debug_type debug_make_reference_type PARAMS ((PTR, debug_type));
/* Make a range of a given type from a lower to an upper bound. */
extern debug_type debug_make_range_type
PARAMS ((PTR, debug_type, bfd_signed_vma, bfd_signed_vma));
/* Make an array type. The second argument is the type of an element
of the array. The third argument is the type of a range of the
array. The fourth and fifth argument are the lower and upper
bounds, respectively (if the bounds are not known, lower should be
0 and upper should be -1). The sixth argument is true if this
array is actually a string, as in C. */
extern debug_type debug_make_array_type
PARAMS ((PTR, debug_type, debug_type, bfd_signed_vma, bfd_signed_vma,
boolean));
/* Make a set of a given type. For example, a Pascal set type. The
boolean argument is true if this set is actually a bitstring, as in
CHILL. */
extern debug_type debug_make_set_type PARAMS ((PTR, debug_type, boolean));
/* Make a type for a pointer which is relative to an object. The
second argument is the type of the object to which the pointer is
relative. The third argument is the type that the pointer points
to. */
extern debug_type debug_make_offset_type
PARAMS ((PTR, debug_type, debug_type));
/* Make a type for a method function. The second argument is the
return type. The third argument is the domain. The fourth
argument is a NULL terminated array of argument types. The fifth
argument is true if the function takes a variable number of
arguments, in which case the array of argument types indicates the
types of the first arguments. The domain and the argument array
may be NULL, in which case this is a stub method and that
information is not available. Stabs debugging uses this, and gets
the argument types from the mangled name. */
extern debug_type debug_make_method_type
PARAMS ((PTR, debug_type, debug_type, debug_type *, boolean));
/* Make a const qualified version of a given type. */
extern debug_type debug_make_const_type PARAMS ((PTR, debug_type));
/* Make a volatile qualified version of a given type. */
extern debug_type debug_make_volatile_type PARAMS ((PTR, debug_type));
/* Make an undefined tagged type. For example, a struct which has
been mentioned, but not defined. */
extern debug_type debug_make_undefined_tagged_type
PARAMS ((PTR, const char *, enum debug_type_kind));
/* Make a base class for an object. The second argument is the base
class type. The third argument is the bit position of this base
class in the object. The fourth argument is whether this is a
virtual class. The fifth argument is the visibility of the base
class. */
extern debug_baseclass debug_make_baseclass
PARAMS ((PTR, debug_type, bfd_vma, boolean, enum debug_visibility));
/* Make a field for a struct. The second argument is the name. The
third argument is the type of the field. The fourth argument is
the bit position of the field. The fifth argument is the size of
the field (it may be zero). The sixth argument is the visibility
of the field. */
extern debug_field debug_make_field
PARAMS ((PTR, const char *, debug_type, bfd_vma, bfd_vma,
enum debug_visibility));
/* Make a static member of an object. The second argument is the
name. The third argument is the type of the member. The fourth
argument is the physical name of the member (i.e., the name as a
global variable). The fifth argument is the visibility of the
member. */
extern debug_field debug_make_static_member
PARAMS ((PTR, const char *, debug_type, const char *,
enum debug_visibility));
/* Make a method. The second argument is the name, and the third
argument is a NULL terminated array of method variants. Each
method variant is a method with this name but with different
argument types. */
extern debug_method debug_make_method
PARAMS ((PTR, const char *, debug_method_variant *));
/* Make a method variant. The second argument is the physical name of
the function. The third argument is the type of the function,
probably constructed by debug_make_method_type. The fourth
argument is the visibility. The fifth argument is whether this is
a const function. The sixth argument is whether this is a volatile
function. The seventh argument is the index in the virtual
function table, if any. The eighth argument is the virtual
function context. */
extern debug_method_variant debug_make_method_variant
PARAMS ((PTR, const char *, debug_type, enum debug_visibility, boolean,
boolean, bfd_vma, debug_type));
/* Make a static method argument. The arguments are the same as for
debug_make_method_variant, except that the last two are omitted
since a static method can not also be virtual. */
extern debug_method_variant debug_make_static_method_variant
PARAMS ((PTR, const char *, debug_type, enum debug_visibility, boolean,
boolean));
/* Name a type. This returns a new type with an attached name. */
extern debug_type debug_name_type PARAMS ((PTR, const char *, debug_type));
/* Give a tag to a type, such as a struct or union. This returns a
new type with an attached tag. */
extern debug_type debug_tag_type PARAMS ((PTR, const char *, debug_type));
/* Record the size of a given type. */
extern boolean debug_record_type_size PARAMS ((PTR, debug_type, unsigned int));
/* Find a named type. */
extern debug_type debug_find_named_type PARAMS ((PTR, const char *));
/* Find a tagged type. */
extern debug_type debug_find_tagged_type
PARAMS ((PTR, const char *, enum debug_type_kind));
/* Get the kind of a type. */
extern enum debug_type_kind debug_get_type_kind PARAMS ((PTR, debug_type));
/* Get the name of a type. */
extern const char *debug_get_type_name PARAMS ((PTR, debug_type));
/* Get the size of a type. */
extern bfd_vma debug_get_type_size PARAMS ((PTR, debug_type));
/* Get the return type of a function or method type. */
extern debug_type debug_get_return_type PARAMS ((PTR, debug_type));
/* Get the NULL terminated array of parameter types for a function or
method type (actually, parameter types are not currently stored for
function types). This may be used to determine whether a method
type is a stub method or not. The last argument points to a
boolean which is set to true if the function takes a variable
number of arguments. */
extern const debug_type *debug_get_parameter_types PARAMS ((PTR,
debug_type,
boolean *));
/* Get the target type of a pointer or reference or const or volatile
type. */
extern debug_type debug_get_target_type PARAMS ((PTR, debug_type));
/* Get the NULL terminated array of fields for a struct, union, or
class. */
extern const debug_field *debug_get_fields PARAMS ((PTR, debug_type));
/* Get the type of a field. */
extern debug_type debug_get_field_type PARAMS ((PTR, debug_field));
/* Get the name of a field. */
extern const char *debug_get_field_name PARAMS ((PTR, debug_field));
/* Get the bit position of a field within the containing structure.
If the field is a static member, this will return (bfd_vma) -1. */
extern bfd_vma debug_get_field_bitpos PARAMS ((PTR, debug_field));
/* Get the bit size of a field. If the field is a static member, this
will return (bfd_vma) -1. */
extern bfd_vma debug_get_field_bitsize PARAMS ((PTR, debug_field));
/* Get the visibility of a field. */
extern enum debug_visibility debug_get_field_visibility
PARAMS ((PTR, debug_field));
/* Get the physical name of a field, if it is a static member. If the
field is not a static member, this will return NULL. */
extern const char *debug_get_field_physname PARAMS ((PTR, debug_field));
/* Write out the recorded debugging information. This takes a set of
function pointers which are called to do the actual writing. The
first PTR is the debugging handle. The second PTR is a handle
which is passed to the functions. */
extern boolean debug_write PARAMS ((PTR, const struct debug_write_fns *, PTR));
#endif /* DEBUG_H */

90
pstack/demangle.h Normal file
View File

@ -0,0 +1,90 @@
/* Defs for interface to demanglers.
Copyright 1992, 1995, 1996 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#if !defined (DEMANGLE_H)
#define DEMANGLE_H
#ifdef IN_GCC
#include "gansidecl.h"
#define PARAMS(ARGS) PROTO(ARGS)
#else /* ! IN_GCC */
#include <ansidecl.h>
#endif /* IN_GCC */
/* Options passed to cplus_demangle (in 2nd parameter). */
#define DMGL_NO_OPTS 0 /* For readability... */
#define DMGL_PARAMS (1 << 0) /* Include function args */
#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
#define DMGL_AUTO (1 << 8)
#define DMGL_GNU (1 << 9)
#define DMGL_LUCID (1 << 10)
#define DMGL_ARM (1 << 11)
/* If none of these are set, use 'current_demangling_style' as the default. */
#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM)
/* Enumeration of possible demangling styles.
Lucid and ARM styles are still kept logically distinct, even though
they now both behave identically. The resulting style is actual the
union of both. I.E. either style recognizes both "__pt__" and "__rf__"
for operator "->", even though the first is lucid style and the second
is ARM style. (FIXME?) */
extern enum demangling_styles
{
unknown_demangling = 0,
auto_demangling = DMGL_AUTO,
gnu_demangling = DMGL_GNU,
lucid_demangling = DMGL_LUCID,
arm_demangling = DMGL_ARM
} current_demangling_style;
/* Define string names for the various demangling styles. */
#define AUTO_DEMANGLING_STYLE_STRING "auto"
#define GNU_DEMANGLING_STYLE_STRING "gnu"
#define LUCID_DEMANGLING_STYLE_STRING "lucid"
#define ARM_DEMANGLING_STYLE_STRING "arm"
/* Some macros to test what demangling style is active. */
#define CURRENT_DEMANGLING_STYLE current_demangling_style
#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO)
#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU)
#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID)
#define ARM_DEMANGLING (CURRENT_DEMANGLING_STYLE & DMGL_ARM)
extern char *
cplus_demangle PARAMS ((const char *mangled, int options));
extern int
cplus_demangle_opname PARAMS ((const char *opname, char *result, int options));
extern const char *
cplus_mangle_opname PARAMS ((const char *opname, int options));
/* Note: This sets global state. FIXME if you care about multi-threading. */
extern void
set_cplus_marker_for_demangling PARAMS ((int ch));
#endif /* DEMANGLE_H */

266
pstack/filemode.c Normal file
View File

@ -0,0 +1,266 @@
/* filemode.c -- make a string describing file modes
Copyright (C) 1985, 90, 91, 94, 95, 1997 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include "bfd.h"
#include "bucomm.h"
static char ftypelet PARAMS ((unsigned long));
static void setst PARAMS ((unsigned long, char *));
/* filemodestring - fill in string STR with an ls-style ASCII
representation of the st_mode field of file stats block STATP.
10 characters are stored in STR; no terminating null is added.
The characters stored in STR are:
0 File type. 'd' for directory, 'c' for character
special, 'b' for block special, 'm' for multiplex,
'l' for symbolic link, 's' for socket, 'p' for fifo,
'-' for any other file type
1 'r' if the owner may read, '-' otherwise.
2 'w' if the owner may write, '-' otherwise.
3 'x' if the owner may execute, 's' if the file is
set-user-id, '-' otherwise.
'S' if the file is set-user-id, but the execute
bit isn't set.
4 'r' if group members may read, '-' otherwise.
5 'w' if group members may write, '-' otherwise.
6 'x' if group members may execute, 's' if the file is
set-group-id, '-' otherwise.
'S' if it is set-group-id but not executable.
7 'r' if any user may read, '-' otherwise.
8 'w' if any user may write, '-' otherwise.
9 'x' if any user may execute, 't' if the file is "sticky"
(will be retained in swap space after execution), '-'
otherwise.
'T' if the file is sticky but not executable. */
#if 0
/* This is not used; only mode_string is used. */
void
filemodestring (statp, str)
struct stat *statp;
char *str;
{
mode_string ((unsigned long) statp->st_mode, str);
}
#endif
/* Get definitions for the file permission bits. */
#ifndef S_IRWXU
#define S_IRWXU 0700
#endif
#ifndef S_IRUSR
#define S_IRUSR 0400
#endif
#ifndef S_IWUSR
#define S_IWUSR 0200
#endif
#ifndef S_IXUSR
#define S_IXUSR 0100
#endif
#ifndef S_IRWXG
#define S_IRWXG 0070
#endif
#ifndef S_IRGRP
#define S_IRGRP 0040
#endif
#ifndef S_IWGRP
#define S_IWGRP 0020
#endif
#ifndef S_IXGRP
#define S_IXGRP 0010
#endif
#ifndef S_IRWXO
#define S_IRWXO 0007
#endif
#ifndef S_IROTH
#define S_IROTH 0004
#endif
#ifndef S_IWOTH
#define S_IWOTH 0002
#endif
#ifndef S_IXOTH
#define S_IXOTH 0001
#endif
/* Like filemodestring, but only the relevant part of the `struct stat'
is given as an argument. */
void
mode_string (mode, str)
unsigned long mode;
char *str;
{
str[0] = ftypelet ((unsigned long) mode);
str[1] = (mode & S_IRUSR) != 0 ? 'r' : '-';
str[2] = (mode & S_IWUSR) != 0 ? 'w' : '-';
str[3] = (mode & S_IXUSR) != 0 ? 'x' : '-';
str[4] = (mode & S_IRGRP) != 0 ? 'r' : '-';
str[5] = (mode & S_IWGRP) != 0 ? 'w' : '-';
str[6] = (mode & S_IXGRP) != 0 ? 'x' : '-';
str[7] = (mode & S_IROTH) != 0 ? 'r' : '-';
str[8] = (mode & S_IWOTH) != 0 ? 'w' : '-';
str[9] = (mode & S_IXOTH) != 0 ? 'x' : '-';
setst ((unsigned long) mode, str);
}
/* Return a character indicating the type of file described by
file mode BITS:
'd' for directories
'b' for block special files
'c' for character special files
'm' for multiplexor files
'l' for symbolic links
's' for sockets
'p' for fifos
'-' for any other file type. */
#ifndef S_ISDIR
#ifdef S_IFDIR
#define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR)
#else /* ! defined (S_IFDIR) */
#define S_ISDIR(i) (((i) & 0170000) == 040000)
#endif /* ! defined (S_IFDIR) */
#endif /* ! defined (S_ISDIR) */
#ifndef S_ISBLK
#ifdef S_IFBLK
#define S_ISBLK(i) (((i) & S_IFMT) == S_IFBLK)
#else /* ! defined (S_IFBLK) */
#define S_ISBLK(i) 0
#endif /* ! defined (S_IFBLK) */
#endif /* ! defined (S_ISBLK) */
#ifndef S_ISCHR
#ifdef S_IFCHR
#define S_ISCHR(i) (((i) & S_IFMT) == S_IFCHR)
#else /* ! defined (S_IFCHR) */
#define S_ISCHR(i) 0
#endif /* ! defined (S_IFCHR) */
#endif /* ! defined (S_ISCHR) */
#ifndef S_ISFIFO
#ifdef S_IFIFO
#define S_ISFIFO(i) (((i) & S_IFMT) == S_IFIFO)
#else /* ! defined (S_IFIFO) */
#define S_ISFIFO(i) 0
#endif /* ! defined (S_IFIFO) */
#endif /* ! defined (S_ISFIFO) */
#ifndef S_ISSOCK
#ifdef S_IFSOCK
#define S_ISSOCK(i) (((i) & S_IFMT) == S_IFSOCK)
#else /* ! defined (S_IFSOCK) */
#define S_ISSOCK(i) 0
#endif /* ! defined (S_IFSOCK) */
#endif /* ! defined (S_ISSOCK) */
#ifndef S_ISLNK
#ifdef S_IFLNK
#define S_ISLNK(i) (((i) & S_IFMT) == S_IFLNK)
#else /* ! defined (S_IFLNK) */
#define S_ISLNK(i) 0
#endif /* ! defined (S_IFLNK) */
#endif /* ! defined (S_ISLNK) */
static char
ftypelet (bits)
unsigned long bits;
{
if (S_ISDIR (bits))
return 'd';
if (S_ISLNK (bits))
return 'l';
if (S_ISBLK (bits))
return 'b';
if (S_ISCHR (bits))
return 'c';
if (S_ISSOCK (bits))
return 's';
if (S_ISFIFO (bits))
return 'p';
#ifdef S_IFMT
#ifdef S_IFMPC
if ((bits & S_IFMT) == S_IFMPC
|| (bits & S_IFMT) == S_IFMPB)
return 'm';
#endif
#ifdef S_IFNWK
if ((bits & S_IFMT) == S_IFNWK)
return 'n';
#endif
#endif
return '-';
}
/* Set the 's' and 't' flags in file attributes string CHARS,
according to the file mode BITS. */
static void
setst (bits, chars)
unsigned long bits;
char *chars;
{
#ifdef S_ISUID
if (bits & S_ISUID)
{
if (chars[3] != 'x')
/* Set-uid, but not executable by owner. */
chars[3] = 'S';
else
chars[3] = 's';
}
#endif
#ifdef S_ISGID
if (bits & S_ISGID)
{
if (chars[6] != 'x')
/* Set-gid, but not executable by group. */
chars[6] = 'S';
else
chars[6] = 's';
}
#endif
#ifdef S_ISVTX
if (bits & S_ISVTX)
{
if (chars[9] != 'x')
/* Sticky, but not executable by others. */
chars[9] = 'T';
else
chars[9] = 't';
}
#endif
}

7602
pstack/ieee.c Normal file

File diff suppressed because it is too large Load Diff

139
pstack/ieee.h Normal file
View File

@ -0,0 +1,139 @@
/* IEEE Standard 695-1980 "Universal Format for Object Modules" header file
Contributed by Cygnus Support. */
#define N_W_VARIABLES 8
#define Module_Beginning 0xe0
typedef struct ieee_module {
char *processor;
char *module_name;
} ieee_module_begin_type;
#define Address_Descriptor 0xec
typedef struct ieee_address {
bfd_vma number_of_bits_mau;
bfd_vma number_of_maus_in_address;
unsigned char byte_order;
#define IEEE_LITTLE 0xcc
#define IEEE_BIG 0xcd
} ieee_address_descriptor_type;
typedef union ieee_w_variable {
file_ptr offset[N_W_VARIABLES];
struct {
file_ptr extension_record;
file_ptr environmental_record;
file_ptr section_part;
file_ptr external_part;
file_ptr debug_information_part;
file_ptr data_part;
file_ptr trailer_part;
file_ptr me_record;
} r;
} ieee_w_variable_type;
typedef enum ieee_record
{
ieee_number_start_enum = 0x00,
ieee_number_end_enum=0x7f,
ieee_number_repeat_start_enum = 0x80,
ieee_number_repeat_end_enum = 0x88,
ieee_number_repeat_4_enum = 0x84,
ieee_number_repeat_3_enum = 0x83,
ieee_number_repeat_2_enum = 0x82,
ieee_number_repeat_1_enum = 0x81,
ieee_module_beginning_enum = 0xe0,
ieee_module_end_enum = 0xe1,
ieee_extension_length_1_enum = 0xde,
ieee_extension_length_2_enum = 0xdf,
ieee_section_type_enum = 0xe6,
ieee_section_alignment_enum = 0xe7,
ieee_external_symbol_enum = 0xe8,
ieee_comma = 0x90,
ieee_external_reference_enum = 0xe9,
ieee_set_current_section_enum = 0xe5,
ieee_address_descriptor_enum = 0xec,
ieee_load_constant_bytes_enum = 0xed,
ieee_load_with_relocation_enum = 0xe4,
ieee_variable_A_enum = 0xc1,
ieee_variable_B_enum = 0xc2,
ieee_variable_C_enum = 0xc3,
ieee_variable_D_enum = 0xc4,
ieee_variable_E_enum = 0xc5,
ieee_variable_F_enum = 0xc6,
ieee_variable_G_enum = 0xc7,
ieee_variable_H_enum = 0xc8,
ieee_variable_I_enum = 0xc9,
ieee_variable_J_enum = 0xca,
ieee_variable_K_enum = 0xcb,
ieee_variable_L_enum = 0xcc,
ieee_variable_M_enum = 0xcd,
ieee_variable_N_enum = 0xce,
ieee_variable_O_enum = 0xcf,
ieee_variable_P_enum = 0xd0,
ieee_variable_Q_enum = 0xd1,
ieee_variable_R_enum = 0xd2,
ieee_variable_S_enum = 0xd3,
ieee_variable_T_enum = 0xd4,
ieee_variable_U_enum = 0xd5,
ieee_variable_V_enum = 0xd6,
ieee_variable_W_enum = 0xd7,
ieee_variable_X_enum = 0xd8,
ieee_variable_Y_enum = 0xd9,
ieee_variable_Z_enum = 0xda,
ieee_function_plus_enum = 0xa5,
ieee_function_minus_enum = 0xa6,
ieee_function_signed_open_b_enum = 0xba,
ieee_function_signed_close_b_enum = 0xbb,
ieee_function_unsigned_open_b_enum = 0xbc,
ieee_function_unsigned_close_b_enum = 0xbd,
ieee_function_either_open_b_enum = 0xbe,
ieee_function_either_close_b_enum = 0xbf,
ieee_record_seperator_enum = 0xdb,
ieee_e2_first_byte_enum = 0xe2,
ieee_section_size_enum = 0xe2d3,
ieee_physical_region_size_enum = 0xe2c1,
ieee_region_base_address_enum = 0xe2c2,
ieee_mau_size_enum = 0xe2c6,
ieee_m_value_enum = 0xe2cd,
ieee_section_base_address_enum = 0xe2cc,
ieee_asn_record_enum = 0xe2ce,
ieee_section_offset_enum = 0xe2d2,
ieee_value_starting_address_enum = 0xe2c7,
ieee_assign_value_to_variable_enum = 0xe2d7,
ieee_set_current_pc_enum = 0xe2d0,
ieee_value_record_enum = 0xe2c9,
ieee_nn_record = 0xf0,
ieee_at_record_enum = 0xf1,
ieee_ty_record_enum = 0xf2,
ieee_attribute_record_enum = 0xf1c9,
ieee_atn_record_enum = 0xf1ce,
ieee_external_reference_info_record_enum = 0xf1d8,
ieee_weak_external_reference_enum= 0xf4,
ieee_repeat_data_enum = 0xf7,
ieee_bb_record_enum = 0xf8,
ieee_be_record_enum = 0xf9
} ieee_record_enum_type;
typedef struct ieee_section {
unsigned int section_index;
unsigned int section_type;
char *section_name;
unsigned int parent_section_index;
unsigned int sibling_section_index;
unsigned int context_index;
} ieee_section_type;
#define IEEE_REFERENCE_BASE 11
#define IEEE_PUBLIC_BASE 32
#define IEEE_SECTION_NUMBER_BASE 1

180
pstack/libiberty.h Normal file
View File

@ -0,0 +1,180 @@
/* Function declarations for libiberty.
Written by Cygnus Support, 1994.
The libiberty library provides a number of functions which are
missing on some operating systems. We do not declare those here,
to avoid conflicts with the system header files on operating
systems that do support those functions. In this file we only
declare those functions which are specific to libiberty. */
#ifndef LIBIBERTY_H
#define LIBIBERTY_H
#ifdef __cplusplus
extern "C" {
#endif
#include "ansidecl.h"
/* Build an argument vector from a string. Allocates memory using
malloc. Use freeargv to free the vector. */
extern char **buildargv PARAMS ((char *));
/* Free a vector returned by buildargv. */
extern void freeargv PARAMS ((char **));
/* Duplicate an argument vector. Allocates memory using malloc. Use
freeargv to free the vector. */
extern char **dupargv PARAMS ((char **));
/* Return the last component of a path name. Note that we can't use a
prototype here because the parameter is declared inconsistently
across different systems, sometimes as "char *" and sometimes as
"const char *" */
#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__)
extern char *basename PARAMS ((const char *));
#else
extern char *basename ();
#endif
/* Concatenate an arbitrary number of strings, up to (char *) NULL.
Allocates memory using xmalloc. */
extern char *concat PARAMS ((const char *, ...));
/* Check whether two file descriptors refer to the same file. */
extern int fdmatch PARAMS ((int fd1, int fd2));
/* Get the amount of time the process has run, in microseconds. */
extern long get_run_time PARAMS ((void));
/* Choose a temporary directory to use for scratch files. */
extern char *choose_temp_base PARAMS ((void));
/* Allocate memory filled with spaces. Allocates using malloc. */
extern const char *spaces PARAMS ((int count));
/* Return the maximum error number for which strerror will return a
string. */
extern int errno_max PARAMS ((void));
/* Return the name of an errno value (e.g., strerrno (EINVAL) returns
"EINVAL"). */
extern const char *strerrno PARAMS ((int));
/* Given the name of an errno value, return the value. */
extern int strtoerrno PARAMS ((const char *));
/* ANSI's strerror(), but more robust. */
extern char *xstrerror PARAMS ((int));
/* Return the maximum signal number for which strsignal will return a
string. */
extern int signo_max PARAMS ((void));
/* Return a signal message string for a signal number
(e.g., strsignal (SIGHUP) returns something like "Hangup"). */
/* This is commented out as it can conflict with one in system headers.
We still document its existence though. */
/*extern const char *strsignal PARAMS ((int));*/
/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns
"SIGHUP"). */
extern const char *strsigno PARAMS ((int));
/* Given the name of a signal, return its number. */
extern int strtosigno PARAMS ((const char *));
/* Register a function to be run by xexit. Returns 0 on success. */
extern int xatexit PARAMS ((void (*fn) (void)));
/* Exit, calling all the functions registered with xatexit. */
#ifndef __GNUC__
extern void xexit PARAMS ((int status));
#else
void xexit PARAMS ((int status)) __attribute__ ((noreturn));
#endif
/* Set the program name used by xmalloc. */
extern void xmalloc_set_program_name PARAMS ((const char *));
/* Allocate memory without fail. If malloc fails, this will print a
message to stderr (using the name set by xmalloc_set_program_name,
if any) and then call xexit. */
#ifdef ANSI_PROTOTYPES
/* Get a definition for size_t. */
#include <stddef.h>
#endif
extern PTR xmalloc PARAMS ((size_t));
/* Reallocate memory without fail. This works like xmalloc.
FIXME: We do not declare the parameter types for the same reason as
xmalloc. */
extern PTR xrealloc PARAMS ((PTR, size_t));
/* Allocate memory without fail and set it to zero. This works like
xmalloc. */
extern PTR xcalloc PARAMS ((size_t, size_t));
/* Copy a string into a memory buffer without fail. */
extern char *xstrdup PARAMS ((const char *));
/* hex character manipulation routines */
#define _hex_array_size 256
#define _hex_bad 99
extern char _hex_value[_hex_array_size];
extern void hex_init PARAMS ((void));
#define hex_p(c) (hex_value (c) != _hex_bad)
/* If you change this, note well: Some code relies on side effects in
the argument being performed exactly once. */
#define hex_value(c) (_hex_value[(unsigned char) (c)])
/* Definitions used by the pexecute routine. */
#define PEXECUTE_FIRST 1
#define PEXECUTE_LAST 2
#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST)
#define PEXECUTE_SEARCH 4
#define PEXECUTE_VERBOSE 8
/* Execute a program. */
extern int pexecute PARAMS ((const char *, char * const *, const char *,
const char *, char **, char **, int));
/* Wait for pexecute to finish. */
extern int pwait PARAMS ((int, int *, int));
#ifdef __cplusplus
}
#endif
#endif /* ! defined (LIBIBERTY_H) */

90
pstack/linuxthreads.c Normal file
View File

@ -0,0 +1,90 @@
/* $Header$ */
/*
* LinuxThreads specific stuff.
*/
#include <sys/types.h>
#include <assert.h>
#include <limits.h> /* PTHREAD_THREADS_MAX */
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sched.h>
#include "linuxthreads.h"
#define AT_INT(intval) *((int32_t*)(intval))
/*
* Internal LinuxThreads variables.
* Official interface exposed to GDB.
*/
#if 1
extern volatile int __pthread_threads_debug;
extern volatile char __pthread_handles;
extern char __pthread_initial_thread;
/*extern volatile Elf32_Sym* __pthread_manager_thread;*/
extern const int __pthread_sizeof_handle;
extern const int __pthread_offsetof_descr;
extern const int __pthread_offsetof_pid;
extern volatile int __pthread_handles_num;
#endif /* 0 */
/*
* Notify others.
*/
int
linuxthreads_notify_others( const int signotify)
{
const pid_t mypid = getpid();
//const pthread_t mytid = pthread_self();
int i;
int threadcount = 0;
int threads[PTHREAD_THREADS_MAX];
int pid;
TRACE_FPRINTF((stderr, "theadcount:%d\n", __pthread_handles_num));
if (__pthread_handles_num==2) {
/* no threads beside the initial thread */
return 0;
}
/*assert(maxthreads>=3);
assert(maxthreads>=__pthread_handles_num+2);*/
// take the initial thread with us
pid = AT_INT(&__pthread_initial_thread + __pthread_offsetof_pid);
if (pid!=mypid && pid!=0)
threads[threadcount++] = pid;
// don't know why, but always handles[0]==handles[1]
for (i=1; i<__pthread_handles_num; ++i) {
const int descr = AT_INT(&__pthread_handles+i*__pthread_sizeof_handle+__pthread_offsetof_descr);
assert(descr!=0);
pid = AT_INT(descr+__pthread_offsetof_pid);
if (pid!=mypid && pid!=0)
threads[threadcount++] = pid;
}
/* TRACE_FPRINTF((stderr, "Stopping threads...")); */
//for (i=0; i<threadcount; ++i) {
// /* TRACE_FPRINTF((stderr, "%d ", threads[i])); */
// fflush(stdout);
// kill(threads[i], SIGSTOP); /* Tell thread to stop */
//}
/* TRACE_FPRINTF((stderr, " done!\n")); */
for (i=0; i<threadcount; ++i) {
TRACE_FPRINTF((stderr, "--- NOTIFYING %d\n", threads[i]));
kill(threads[i], signotify); /* Tell to print stack trace */
/* TRACE_FPRINTF((stderr, "--- WAITING FOR %d\n", threads[i])); */
/*pause(); Wait for confirmation. */
}
for (i=0; i<threadcount; ++i)
sched_yield();
for (i=0; i<threadcount; ++i) {
TRACE_FPRINTF((stderr, "--- KILLING %d\n", threads[i]));
kill(threads[i], SIGKILL); /* Tell thread die :) */
}
return __pthread_handles_num;
}

28
pstack/linuxthreads.h Normal file
View File

@ -0,0 +1,28 @@
/* $Header$ */
/*
* LinuxThreads specific stuff.
*/
#ifndef pstack_linuxthreads_h_
#define pstack_linuxthreads_h_
#include <pthread.h>
#include "pstacktrace.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Tell other threads to dump stacks...
*/
int
linuxthreads_notify_others( const int signotify);
#ifdef __cplusplus
}
#endif
#endif /* pstack_linuxthreads_h_ */

2746
pstack/pstack.c Normal file

File diff suppressed because it is too large Load Diff

22
pstack/pstack.h Normal file
View File

@ -0,0 +1,22 @@
/* $Header$ */
#ifndef pstack_pstack_h_
#define pstack_pstack_h_
#include "pstacktrace.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Install the stack-trace-on-SEGV handler....
*/
extern int
pstack_install_segv_action( const char* path_format);
#ifdef __cplusplus
}
#endif
#endif /* pstack_pstack_h_ */

24
pstack/pstacktrace.h Normal file
View File

@ -0,0 +1,24 @@
/* $Header$ */
/*
* Debugging macros.
*/
#ifndef pstacktrace_h_
#define pstacktrace_h_
#define PSTACK_DEBUG 1
#undef PSTACK_DEBUG
#ifdef PSTACK_DEBUG
# define TRACE_PUTC(a) putc a
# define TRACE_FPUTS(a) fputs a
# define TRACE_FPRINTF(a) fprintf a
#else /* PSTACK_DEBUG */
# define TRACE_PUTC(a) (void)0
# define TRACE_FPUTS(a) (void)0
# define TRACE_FPRINTF(a) (void)0
#endif /* !PSTACK_DEBUG */
#endif /* pstacktrace_h_ */

462
pstack/rddbg.c Normal file
View File

@ -0,0 +1,462 @@
/* rddbg.c -- Read debugging information into a generic form.
Copyright (C) 1995, 96, 1997 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* This file reads debugging information into a generic form. This
file knows how to dig the debugging information out of an object
file. */
#include <bfd.h>
#include "bucomm.h"
#include <libiberty.h>
#include "debug.h"
#include "budbg.h"
static boolean read_section_stabs_debugging_info
PARAMS ((bfd *, asymbol **, long, PTR, boolean *));
static boolean read_symbol_stabs_debugging_info
PARAMS ((bfd *, asymbol **, long, PTR, boolean *));
static boolean read_ieee_debugging_info PARAMS ((bfd *, PTR, boolean *));
static void save_stab PARAMS ((int, int, bfd_vma, const char *));
static void stab_context PARAMS ((void));
static void free_saved_stabs PARAMS ((void));
/* Read debugging information from a BFD. Returns a generic debugging
pointer. */
PTR
read_debugging_info (abfd, syms, symcount)
bfd *abfd;
asymbol **syms;
long symcount;
{
PTR dhandle;
boolean found;
dhandle = debug_init ();
if (dhandle == NULL)
return NULL;
if (! read_section_stabs_debugging_info (abfd, syms, symcount, dhandle,
&found))
return NULL;
if (bfd_get_flavour (abfd) == bfd_target_aout_flavour)
{
if (! read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle,
&found))
return NULL;
}
if (bfd_get_flavour (abfd) == bfd_target_ieee_flavour)
{
if (! read_ieee_debugging_info (abfd, dhandle, &found))
return NULL;
}
/* Try reading the COFF symbols if we didn't find any stabs in COFF
sections. */
if (! found
&& bfd_get_flavour (abfd) == bfd_target_coff_flavour
&& symcount > 0)
{
#if 0
/*
* JZ: Do we need coff?
*/
if (! parse_coff (abfd, syms, symcount, dhandle))
#else
fprintf (stderr, "%s: COFF support temporarily disabled\n",
bfd_get_filename (abfd));
return NULL;
#endif
return NULL;
found = true;
}
if (! found)
{
fprintf (stderr, "%s: no recognized debugging information\n",
bfd_get_filename (abfd));
return NULL;
}
return dhandle;
}
/* Read stabs in sections debugging information from a BFD. */
static boolean
read_section_stabs_debugging_info (abfd, syms, symcount, dhandle, pfound)
bfd *abfd;
asymbol **syms;
long symcount;
PTR dhandle;
boolean *pfound;
{
static struct
{
const char *secname;
const char *strsecname;
} names[] = { { ".stab", ".stabstr" } };
unsigned int i;
PTR shandle;
*pfound = false;
shandle = NULL;
for (i = 0; i < sizeof names / sizeof names[0]; i++)
{
asection *sec, *strsec;
sec = bfd_get_section_by_name (abfd, names[i].secname);
strsec = bfd_get_section_by_name (abfd, names[i].strsecname);
if (sec != NULL && strsec != NULL)
{
bfd_size_type stabsize, strsize;
bfd_byte *stabs, *strings;
bfd_byte *stab;
bfd_size_type stroff, next_stroff;
stabsize = bfd_section_size (abfd, sec);
stabs = (bfd_byte *) xmalloc (stabsize);
if (! bfd_get_section_contents (abfd, sec, stabs, 0, stabsize))
{
fprintf (stderr, "%s: %s: %s\n",
bfd_get_filename (abfd), names[i].secname,
bfd_errmsg (bfd_get_error ()));
return false;
}
strsize = bfd_section_size (abfd, strsec);
strings = (bfd_byte *) xmalloc (strsize);
if (! bfd_get_section_contents (abfd, strsec, strings, 0, strsize))
{
fprintf (stderr, "%s: %s: %s\n",
bfd_get_filename (abfd), names[i].strsecname,
bfd_errmsg (bfd_get_error ()));
return false;
}
if (shandle == NULL)
{
shandle = start_stab (dhandle, abfd, true, syms, symcount);
if (shandle == NULL)
return false;
}
*pfound = true;
stroff = 0;
next_stroff = 0;
for (stab = stabs; stab < stabs + stabsize; stab += 12)
{
bfd_size_type strx;
int type;
int other;
int desc;
bfd_vma value;
/* This code presumes 32 bit values. */
strx = bfd_get_32 (abfd, stab);
type = bfd_get_8 (abfd, stab + 4);
other = bfd_get_8 (abfd, stab + 5);
desc = bfd_get_16 (abfd, stab + 6);
value = bfd_get_32 (abfd, stab + 8);
if (type == 0)
{
/* Special type 0 stabs indicate the offset to the
next string table. */
stroff = next_stroff;
next_stroff += value;
}
else
{
char *f, *s;
f = NULL;
s = (char *) strings + stroff + strx;
while (s[strlen (s) - 1] == '\\'
&& stab + 12 < stabs + stabsize)
{
char *p;
stab += 12;
p = s + strlen (s) - 1;
*p = '\0';
s = concat (s,
((char *) strings
+ stroff
+ bfd_get_32 (abfd, stab)),
(const char *) NULL);
/* We have to restore the backslash, because, if
the linker is hashing stabs strings, we may
see the same string more than once. */
*p = '\\';
if (f != NULL)
free (f);
f = s;
}
save_stab (type, desc, value, s);
if (! parse_stab (dhandle, shandle, type, desc, value, s))
{
#if 0
/*
* JZ: skip the junk.
*/
stab_context ();
free_saved_stabs ();
return false;
#endif
}
/* Don't free f, since I think the stabs code
expects strings to hang around. This should be
straightened out. FIXME. */
}
}
free_saved_stabs ();
free (stabs);
/* Don't free strings, since I think the stabs code expects
the strings to hang around. This should be straightened
out. FIXME. */
}
}
if (shandle != NULL)
{
if (! finish_stab (dhandle, shandle))
return false;
}
return true;
}
/* Read stabs in the symbol table. */
static boolean
read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle, pfound)
bfd *abfd;
asymbol **syms;
long symcount;
PTR dhandle;
boolean *pfound;
{
PTR shandle;
asymbol **ps, **symend;
shandle = NULL;
symend = syms + symcount;
for (ps = syms; ps < symend; ps++)
{
symbol_info i;
bfd_get_symbol_info (abfd, *ps, &i);
if (i.type == '-')
{
const char *s;
char *f;
if (shandle == NULL)
{
shandle = start_stab (dhandle, abfd, false, syms, symcount);
if (shandle == NULL)
return false;
}
*pfound = true;
s = i.name;
f = NULL;
while (s[strlen (s) - 1] == '\\'
&& ps + 1 < symend)
{
char *sc, *n;
++ps;
sc = xstrdup (s);
sc[strlen (sc) - 1] = '\0';
n = concat (sc, bfd_asymbol_name (*ps), (const char *) NULL);
free (sc);
if (f != NULL)
free (f);
f = n;
s = n;
}
save_stab (i.stab_type, i.stab_desc, i.value, s);
if (! parse_stab (dhandle, shandle, i.stab_type, i.stab_desc,
i.value, s))
{
stab_context ();
free_saved_stabs ();
return false;
}
/* Don't free f, since I think the stabs code expects
strings to hang around. This should be straightened out.
FIXME. */
}
}
free_saved_stabs ();
if (shandle != NULL)
{
if (! finish_stab (dhandle, shandle))
return false;
}
return true;
}
/* Read IEEE debugging information. */
static boolean
read_ieee_debugging_info (abfd, dhandle, pfound)
bfd *abfd;
PTR dhandle;
boolean *pfound;
{
asection *dsec;
bfd_size_type size;
bfd_byte *contents;
/* The BFD backend puts the debugging information into a section
named .debug. */
dsec = bfd_get_section_by_name (abfd, ".debug");
if (dsec == NULL)
return true;
size = bfd_section_size (abfd, dsec);
contents = (bfd_byte *) xmalloc (size);
if (! bfd_get_section_contents (abfd, dsec, contents, 0, size))
return false;
if (! parse_ieee (dhandle, abfd, contents, size))
return false;
free (contents);
*pfound = true;
return true;
}
/* Record stabs strings, so that we can give some context for errors. */
#define SAVE_STABS_COUNT (16)
struct saved_stab
{
int type;
int desc;
bfd_vma value;
char *string;
};
static struct saved_stab saved_stabs[SAVE_STABS_COUNT];
static int saved_stabs_index;
/* Save a stabs string. */
static void
save_stab (type, desc, value, string)
int type;
int desc;
bfd_vma value;
const char *string;
{
if (saved_stabs[saved_stabs_index].string != NULL)
free (saved_stabs[saved_stabs_index].string);
saved_stabs[saved_stabs_index].type = type;
saved_stabs[saved_stabs_index].desc = desc;
saved_stabs[saved_stabs_index].value = value;
saved_stabs[saved_stabs_index].string = xstrdup (string);
saved_stabs_index = (saved_stabs_index + 1) % SAVE_STABS_COUNT;
}
/* Provide context for an error. */
static void
stab_context ()
{
int i;
fprintf (stderr, "Last stabs entries before error:\n");
fprintf (stderr, "n_type n_desc n_value string\n");
i = saved_stabs_index;
do
{
struct saved_stab *stabp;
stabp = saved_stabs + i;
if (stabp->string != NULL)
{
const char *s;
s = bfd_get_stab_name (stabp->type);
if (s != NULL)
fprintf (stderr, "%-6s", s);
else if (stabp->type == 0)
fprintf (stderr, "HdrSym");
else
fprintf (stderr, "%-6d", stabp->type);
fprintf (stderr, " %-6d ", stabp->desc);
fprintf_vma (stderr, stabp->value);
if (stabp->type != 0)
fprintf (stderr, " %s", stabp->string);
fprintf (stderr, "\n");
}
i = (i + 1) % SAVE_STABS_COUNT;
}
while (i != saved_stabs_index);
}
/* Free the saved stab strings. */
static void
free_saved_stabs ()
{
int i;
for (i = 0; i < SAVE_STABS_COUNT; i++)
{
if (saved_stabs[i].string != NULL)
{
free (saved_stabs[i].string);
saved_stabs[i].string = NULL;
}
}
saved_stabs_index = 0;
}

5082
pstack/stabs.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,8 @@
2000-12-07 Jeremy Cole <jeremy@mysql.com>
* Added UPDATE ... ORDER BY ...
* Added DELETE ... ORDER BY ...
2000-11-11 Jeremy Cole <jeremy@mysql.com>
* Added ALTER TABLE ... ORDER BY ...

View File

@ -41,7 +41,8 @@ LDADD = ../isam/libnisam.a \
../regex/libregex.a \
../strings/libmystrings.a
mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \
@bdb_libs@ @innobase_libs@ @gemini_libs@ \
@bdb_libs@ @innobase_libs@ @pstack_libs@ \
@gemini_libs@ \
$(LDADD) $(CXXLDFLAGS) $(WRAPLIBS)
noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
item_strfunc.h item_timefunc.h item_uniq.h \

View File

@ -241,6 +241,8 @@ void end_thread(THD *thd,bool put_in_cache);
void flush_thread_cache();
void mysql_execute_command(void);
bool do_command(THD *thd);
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length);
bool check_stack_overrun(THD *thd,char *dummy);
bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables);
void mysql_rm_db(THD *thd,char *db,bool if_exists);
@ -251,6 +253,7 @@ void kill_mysql(void);
void close_connection(NET *net,uint errcode=0,bool lock=1);
bool check_access(THD *thd,uint access,const char *db=0,uint *save_priv=0,
bool no_grant=0);
bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables);
bool check_process_priv(THD *thd=0);
int generate_table(THD *thd, TABLE_LIST *table_list,
@ -336,15 +339,16 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &values,COND *conds, ha_rows limit,
List<Item> &values,COND *conds,
ORDER *order, ha_rows limit,
enum enum_duplicates handle_duplicates,
thr_lock_type lock_type);
int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
List<List_item> &values, enum_duplicates flag,
thr_lock_type lock_type);
void kill_delayed_threads(void);
int mysql_delete(THD *thd,TABLE_LIST *table,COND *conds,ha_rows rows,
thr_lock_type lock_type, ulong options);
int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, ORDER *order,
ha_rows rows, thr_lock_type lock_type, ulong options);
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update);
TABLE *open_table(THD *thd,const char *db,const char *table,const char *alias,
bool *refresh);
@ -365,7 +369,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
/* sql_list.c */
int mysqld_show_dbs(THD *thd,const char *wild);
int mysqld_show_open_tables(THD *thd,const char *db,const char *wild);
int mysqld_show_open_tables(THD *thd,const char *wild);
int mysqld_show_tables(THD *thd,const char *db,const char *wild);
int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild);
int mysqld_show_fields(THD *thd,TABLE_LIST *table, const char *wild,
@ -432,8 +436,7 @@ bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables);
void copy_field_from_tmp_record(Field *field,int offset);
int fill_record(List<Item> &fields,List<Item> &values);
int fill_record(Field **field,List<Item> &values);
int list_open_tables(THD *thd,List<char> *files, const char *db,const char *wild);
char* query_table_status(THD *thd,const char *db,const char *table_name);
OPEN_TABLE_LIST *list_open_tables(THD *thd,const char *wild);
/* sql_calc.cc */
bool eval_const_cond(COND *cond);

View File

@ -37,6 +37,13 @@
#define ONE_THREAD
#endif
/* do stack traces are only supported on linux intel */
#if defined(__linux__) && defined(__i386__) && defined(USE_PSTACK)
#define HAVE_STACK_TRACE_ON_SEGV
#include "../pstack/pstack.h"
char pstack_file_name[80];
#endif /* __linux__ */
extern "C" { // Because of SCO 3.2V4.2
#include <errno.h>
#include <sys/stat.h>
@ -179,6 +186,7 @@ SHOW_COMP_OPTION have_ssl=SHOW_OPTION_NO;
static bool opt_skip_slave_start = 0; // if set, slave is not autostarted
static bool opt_do_pstack = 0;
static ulong opt_specialflag=SPECIAL_ENGLISH;
static my_socket unix_sock= INVALID_SOCKET,ip_sock= INVALID_SOCKET;
static ulong back_log,connect_timeout,concurrency;
@ -226,7 +234,7 @@ uint32 server_id = 0;
bool server_id_supplied = 0;
uint mysql_port;
uint test_flags, select_errors=0, dropping_tables=0,ha_open_options=0;
uint test_flags = 0, select_errors=0, dropping_tables=0,ha_open_options=0;
uint volatile thread_count=0, thread_running=0, kill_cached_threads=0,
wake_thread=0, global_read_lock=0;
ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL |
@ -1105,7 +1113,7 @@ static void start_signal_handler(void)
#ifdef HAVE_LINUXTHREADS
static sig_handler write_core(int sig);
#ifdef __i386__
#if defined(__i386__) && !defined(HAVE_STACK_TRACE_ON_SEGV)
#define SIGRETURN_FRAME_COUNT 1
#define PTR_SANE(p) ((char*)p >= heap_start && (char*)p <= heap_end)
@ -1116,14 +1124,14 @@ inline __volatile__ void print_str(const char* name,
const char* val, int max_len)
{
fprintf(stderr, "%s at %p ", name, val);
if(!PTR_SANE(val))
{
fprintf(stderr, " is invalid pointer\n");
return;
}
if (!PTR_SANE(val))
{
fprintf(stderr, " is invalid pointer\n");
return;
}
fprintf(stderr, "= ");
for(; max_len && PTR_SANE(val) && *val; --max_len)
for (; max_len && PTR_SANE(val) && *val; --max_len)
fputc(*val++, stderr);
fputc('\n', stderr);
}
@ -1183,8 +1191,7 @@ New value of ebp failed sanity check, terminating backtrace!\n");
ebp = new_ebp;
++frame_count;
}
fprintf(stderr, "Stack trace successful, trying to get some variables.\n\
fprintf(stderr, "Stack trace successful, tryint to get some variables.\n\
Some pointers may be invalid and cause the dump to abort...\n");
heap_start = __bss_start;
heap_end = (char*)sbrk(0);
@ -1197,7 +1204,7 @@ In some cases of really bad corruption, this value may be invalid\n",
fprintf(stderr, "Please use the information above to create a repeatable\n\
test case for the crash, and send it to bugs@lists.mysql.com\n");
}
#endif
#endif /* HAVE_LINUXTHREADS */
#endif
static sig_handler handle_segfault(int sig)
@ -1215,10 +1222,10 @@ The manual section 'Debugging a MySQL server' tells you how to use a\n\
stack trace and/or the core file to produce a readable backtrace that may\n\
help in finding out why mysqld died.\n",sig);
#if defined(HAVE_LINUXTHREADS)
#ifdef __i386__
#if defined(__i386__) && !defined(HAVE_STACK_TRACE_ON_SEGV)
trace_stack();
fflush(stderr);
#endif /* __i386__ */
fflush(stderr);
#endif /* __i386__ && !HAVE_STACK_TRACE_ON_SEGV */
if (test_flags & TEST_CORE_ON_SIGNAL)
write_core(sig);
#endif /* HAVE_LINUXTHREADS */
@ -1353,6 +1360,13 @@ static void *signal_hand(void *arg __attribute__((unused)))
(void) my_close(pidFile,MYF(0));
}
}
#ifdef HAVE_STACK_TRACE_ON_SEGV
if (opt_do_pstack)
{
sprintf(pstack_file_name,"mysqld-%lu-%%d-%%d.backtrace", (ulong)getpid());
pstack_install_segv_action(pstack_file_name);
}
#endif /* HAVE_STACK_TRACE_ON_SEGV */
// signal to start_signal_handler that we are ready
(void) pthread_mutex_lock(&LOCK_thread_count);
@ -1748,7 +1762,7 @@ The server will not act as a slave.");
LOG_BIN);
using_update_log=1;
}
if (opt_slow_log)
open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log",
LOG_NORMAL);
@ -1770,7 +1784,7 @@ The server will not act as a slave.");
}
#else
locked_in_memory=0;
#endif
#endif
if (opt_myisam_log)
(void) mi_log( 1 );
@ -2024,7 +2038,7 @@ static int bootstrap(FILE *file)
if (pthread_create(&thd->real_id,&connection_attrib,handle_bootstrap,
(void*) thd))
{
sql_print_error("Warning: Can't create thread to handle bootstrap");
sql_print_error("Warning: Can't create thread to handle bootstrap");
return -1;
}
/* Wait for thread to die */
@ -2462,7 +2476,7 @@ enum options {
OPT_INNOBASE_FLUSH_LOG_AT_TRX_COMMIT,
OPT_SAFE_SHOW_DB,
OPT_GEMINI_SKIP, OPT_INNOBASE_SKIP,
OPT_TEMP_POOL, OPT_TX_ISOLATION,
OPT_TEMP_POOL, OPT_DO_PSTACK, OPT_TX_ISOLATION,
OPT_GEMINI_FLUSH_LOG, OPT_GEMINI_RECOVER,
OPT_GEMINI_UNBUFFERED_IO, OPT_SKIP_SAFEMALLOC,
};
@ -2498,6 +2512,8 @@ static struct option long_options[] = {
{"default-table-type", required_argument, 0, (int) OPT_TABLE_TYPE},
{"delay-key-write-for-all-tables",
no_argument, 0, (int) OPT_DELAY_KEY_WRITE},
{"do-pstack",
no_argument, 0, (int) OPT_DO_PSTACK},
{"enable-locking", no_argument, 0, (int) OPT_ENABLE_LOCK},
{"exit-info", optional_argument, 0, 'T'},
{"flush", no_argument, 0, (int) OPT_FLUSH},
@ -2551,7 +2567,7 @@ static struct option long_options[] = {
#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
{"safemalloc-mem-limit", required_argument, 0, (int)
OPT_SAFEMALLOC_MEM_LIMIT},
#endif
#endif
{"new", no_argument, 0, 'n'},
{"old-protocol", no_argument, 0, 'o'},
#ifdef ONE_THREAD
@ -2719,7 +2735,7 @@ CHANGEABLE_VAR changeable_vars[] = {
16384, 1024, 1024*1024L, MALLOC_OVERHEAD, 1024 },
{ "net_retry_count", (long*) &mysqld_net_retry_count,
MYSQLD_NET_RETRY_COUNT, 1, ~0L, 0, 1 },
{ "net_read_timeout", (long*) &net_read_timeout,
{ "net_read_timeout", (long*) &net_read_timeout,
NET_READ_TIMEOUT, 1, 65535, 0, 1 },
{ "net_write_timeout", (long*) &net_write_timeout,
NET_WRITE_TIMEOUT, 1, 65535, 0, 1 },
@ -2729,7 +2745,7 @@ CHANGEABLE_VAR changeable_vars[] = {
0, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, IO_SIZE },
{ "record_buffer", (long*) &my_default_record_cache_size,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE },
{ "slow_launch_time", (long*) &slow_launch_time,
{ "slow_launch_time", (long*) &slow_launch_time,
2L, 0L, ~0L, 0, 1 },
{ "sort_buffer", (long*) &sortbuff_size,
MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0L, MALLOC_OVERHEAD, 1 },
@ -2804,7 +2820,7 @@ struct show_var_st init_vars[]= {
{"join_buffer_size", (char*) &join_buff_size, SHOW_LONG},
{"key_buffer_size", (char*) &keybuff_size, SHOW_LONG},
{"language", language, SHOW_CHAR},
{"large_files_support", (char*) &opt_large_files, SHOW_BOOL},
{"large_files_support", (char*) &opt_large_files, SHOW_BOOL},
#ifdef HAVE_MLOCKALL
{"locked_in_memory", (char*) &locked_in_memory, SHOW_BOOL},
#endif
@ -2936,7 +2952,7 @@ static void use_help(void)
{
print_version();
printf("Use '--help' or '--no-defaults --help' for a list of available options\n");
}
}
static void usage(void)
{
@ -3207,11 +3223,11 @@ static void get_options(int argc,char **argv)
case 'P':
mysql_port= (unsigned int) atoi(optarg);
break;
#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
case OPT_SAFEMALLOC_MEM_LIMIT:
safemalloc_mem_limit = atoi(optarg);
break;
#endif
#endif
case OPT_SOCKET:
mysql_unix_port= optarg;
break;
@ -3281,14 +3297,14 @@ static void get_options(int argc,char **argv)
break;
// needs to be handled (as no-op) in non-debugging mode for test suite
case (int)OPT_DISCONNECT_SLAVE_EVENT_COUNT:
#ifndef DBUG_OFF
#ifndef DBUG_OFF
disconnect_slave_event_count = atoi(optarg);
#endif
#endif
break;
case (int)OPT_ABORT_SLAVE_EVENT_COUNT:
#ifndef DBUG_OFF
#ifndef DBUG_OFF
abort_slave_event_count = atoi(optarg);
#endif
#endif
break;
case (int) OPT_LOG_SLAVE_UPDATES:
opt_log_slave_updates = 1;
@ -3629,11 +3645,11 @@ static void get_options(int argc,char **argv)
#endif
break;
case OPT_INNOBASE_SKIP:
#ifdef HAVE_INNOBASE_DB
#ifdef HAVE_INNOBASE_DB
innobase_skip=1;
have_innobase=SHOW_OPTION_DISABLED;
#endif
break;
break;
case OPT_INNOBASE_DATA_FILE_PATH:
#ifdef HAVE_INNOBASE_DB
innobase_data_file_path=optarg;
@ -3656,6 +3672,9 @@ static void get_options(int argc,char **argv)
innobase_flush_log_at_trx_commit= optarg ? test(atoi(optarg)) : 1;
break;
#endif /* HAVE_INNOBASE_DB */
case OPT_DO_PSTACK:
opt_do_pstack = 1;
break;
case OPT_MYISAM_RECOVER:
{
if (!optarg || !optarg[0])

View File

@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
@ -22,6 +22,11 @@
** 3 byte length & 1 byte package-number.
*/
#ifdef EMBEDDED_LIBRARY
#define net_read_timeout net_read_timeout1
#define net_write_timeout net_write_timeout1
#endif
#ifdef __WIN__
#include <winsock.h>
#endif
@ -35,13 +40,21 @@
#include <errno.h>
#include <sys/types.h>
#include <violite.h>
#include <assert.h>
#ifdef MYSQL_SERVER
ulong max_allowed_packet=65536;
extern ulong net_read_timeout,net_write_timeout;
extern uint test_flags;
#else
ulong max_allowed_packet=16*1024*1024L;
/*
** Give error if a too big packet is found
** The server can change this with the -O switch, but because the client
** can't normally do this the client should have a bigger max_allowed_packet.
*/
ulong max_allowed_packet=~0L;
ulong net_read_timeout= NET_READ_TIMEOUT;
ulong net_write_timeout= NET_WRITE_TIMEOUT;
#endif
@ -50,7 +63,7 @@ ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
#if !defined(__WIN__) && !defined(MSDOS)
#include <sys/socket.h>
#else
#undef MYSQL_SERVER // Win32 can't handle interrupts
#undef MYSQL_SERVER /* Win32 can't handle interrupts */
#endif
#if !defined(MSDOS) && !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__)
#include <netinet/in_systm.h>
@ -84,28 +97,25 @@ inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __a
#endif
#ifdef MYSQL_SERVER
extern ulong bytes_sent, bytes_received;
extern ulong bytes_sent, bytes_received;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
#else
#undef statistic_add
#define statistic_add(A,B,C)
#endif
/*
** Give error if a too big packet is found
** The server can change this with the -O switch, but because the client
** can't normally do this the client should have a bigger max-buffer.
*/
#define TEST_BLOCKING 8
static int net_write_buff(NET *net,const char *packet,uint len);
static int net_write_buff(NET *net,const char *packet,ulong len);
#define MAX_THREE_BYTES 255L*255L*255L
/* Init with packet info */
int my_net_init(NET *net, Vio* vio)
{
if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME))))
if (!(net->buff=(uchar*) my_malloc(net_buffer_length+
NET_HEADER_SIZE + COMP_HEADER_SIZE,
MYF(MY_WME))))
return 1;
if (net_buffer_length > max_allowed_packet)
max_allowed_packet=net_buffer_length;
@ -152,8 +162,12 @@ static my_bool net_realloc(NET *net, ulong length)
net->last_errno=ER_NET_PACKET_TOO_LARGE;
return 1;
}
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
/* We must allocate some extra bytes for the end 0 and to be able to
read big compressed blocks */
if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length +
NET_HEADER_SIZE + COMP_HEADER_SIZE,
MYF(MY_WME))))
{
net->error=1;
#ifdef MYSQL_SERVER
@ -209,18 +223,34 @@ int net_flush(NET *net)
** Write something to server/client buffer
*****************************************************************************/
/*
** Write a logical packet with packet header
** Format: Packet length (3 bytes), packet number(1 byte)
** When compression is used a 3 byte compression length is added
** NOTE: If compression is used the original package is destroyed!
** NOTE: If compression is used the original package is modified!
*/
int
my_net_write(NET *net,const char *packet,ulong len)
{
uchar buff[NET_HEADER_SIZE];
/*
Big packets are handled by splitting them in packets of MAX_THREE_BYTES
length. The last packet is always a packet that is < MAX_THREE_BYTES.
(The last packet may even have a lengt of 0)
*/
while (len >= MAX_THREE_BYTES)
{
const ulong z_size = MAX_THREE_BYTES;
int3store(buff, z_size);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
if (net_write_buff(net, (char*) buff, NET_HEADER_SIZE) ||
net_write_buff(net, packet, z_size))
return 1;
packet += z_size;
len-= z_size;
}
/* Write last packet */
int3store(buff,len);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
@ -228,23 +258,54 @@ my_net_write(NET *net,const char *packet,ulong len)
return net_write_buff(net,packet,len);
}
/*
Send a command to the server.
As the command is part of the first data packet, we have to do some data
juggling to put the command in there, without having to create a new
packet.
This function will split big packets into sub-packets if needed.
(Each sub packet can only be 2^24 bytes)
*/
int
net_write_command(NET *net,uchar command,const char *packet,ulong len)
{
uchar buff[NET_HEADER_SIZE+1];
uint length=len+1; /* 1 extra byte for command */
uchar buff[NET_HEADER_SIZE+1];
uint header_size=NET_HEADER_SIZE+1;
buff[4]=command; /* For first packet */
if (length >= MAX_THREE_BYTES)
{
/* Take into account that we have the command in the first header */
len= MAX_THREE_BYTES -1;
do
{
int3store(buff, MAX_THREE_BYTES);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
if (net_write_buff(net,(char*) buff, header_size) ||
net_write_buff(net,packet,len))
return 1;
packet+= len;
length-= MAX_THREE_BYTES;
len=MAX_THREE_BYTES;
header_size=NET_HEADER_SIZE;
} while (length >= MAX_THREE_BYTES);
len=length; /* Data left to be written */
}
int3store(buff,length);
buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
buff[4]=command;
if (net_write_buff(net,(char*) buff,5))
return 1;
return test(net_write_buff(net,packet,len) || net_flush(net));
return test(net_write_buff(net,(char*) buff,header_size) ||
net_write_buff(net,packet,len) || net_flush(net));
}
/*
Caching the data in a local buffer before sending it.
One can force the buffer to be flushed with 'net_flush'.
*/
static int
net_write_buff(NET *net,const char *packet,uint len)
net_write_buff(NET *net,const char *packet,ulong len)
{
uint left_length=(uint) (net->buff_end - net->write_pos);
@ -263,7 +324,11 @@ net_write_buff(NET *net,const char *packet,uint len)
return 0;
}
/* Read and write using timeouts */
/*
Read and write one packet using timeouts.
If needed, the packet is compressed before sending.
*/
int
net_real_write(NET *net,const char *packet,ulong len)
@ -418,7 +483,7 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
{
if (!thr_alarm(alarmed,net->timeout,&alarm_buff) ||
(!vio_is_blocking(net->vio) && vio_blocking(net->vio,TRUE) < 0))
return; // Can't setup, abort
return; /* Can't setup, abort */
}
while (remain > 0)
{
@ -426,20 +491,26 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
if ((int) (length=vio_read(net->vio,(char*) net->buff,remain)) <= 0L)
{
my_bool interrupted = vio_should_retry(net->vio);
if (!thr_got_alarm(alarmed) && interrupted)
{ /* Probably in MIT threads */
if (!thr_got_alarm(&alarmed) && interrupted)
{ /* Probably in MIT threads */
if (retry_count++ < RETRY_COUNT)
continue;
}
return;
}
remain -=(ulong) length;
statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
remain -= length;
statistic_add(bytes_received,length,&LOCK_bytes_received);
}
}
#endif /* MYSQL_SERVER */
/*
Reads one packet to net->buff + net->where_b
Returns length of packet. Long packets are handled by my_net_read().
This function reallocates the net->buff buffer if necessary.
*/
static uint
my_real_read(NET *net, ulong *complen)
{
@ -576,12 +647,13 @@ my_real_read(NET *net, ulong *complen)
#endif
len=uint3korr(net->buff+net->where_b);
if (!len) /* End of big multi-packet */
goto end;
helping = max(len,*complen) + net->where_b;
/* The necessary size of net->buff */
if (helping >= net->max_packet)
{
/* We must allocate one extra byte for the end null */
if (net_realloc(net,helping+1))
if (net_realloc(net,helping))
{
#ifdef MYSQL_SERVER
if (i == 1)
@ -606,7 +678,21 @@ end:
return(len);
}
uint
/*
Read a packet from the client/server and return it without the internal
package header.
If the packet is the first packet of a multi-packet packet
(which is indicated by the length of the packet = 0xffffff) then
all sub packets are read and concatenated.
If the packet was compressed, its uncompressed and the length of the
uncompressed packet is returned.
The function returns the length of the found packet or packet_error.
net->read_pos points to the read data.
*/
ulong
my_net_read(NET *net)
{
ulong len,complen;
@ -615,65 +701,126 @@ my_net_read(NET *net)
if (!net->compress)
{
#endif
len = my_real_read (net,&complen);
len = my_real_read(net,&complen);
if (len == MAX_THREE_BYTES)
{
/* First packet of a multi-packet. Concatenate the packets */
int save_pos = net->where_b;
ulong total_length=0;
do
{
net->where_b += len;
total_length += len;
len = my_real_read (net,&complen);
} while (len == MAX_THREE_BYTES);
if (len != packet_error)
len+= total_length;
net->where_b = save_pos;
}
net->read_pos = net->buff + net->where_b;
if (len != packet_error)
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
return len;
#ifdef HAVE_COMPRESS
}
if (net->remain_in_buf)
net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
for (;;)
else
{
/* We are using the compressed protocol */
ulong buf_length= net->buf_length;
ulong start_of_packet= net->buf_length - net->remain_in_buf;
ulong first_packet_offset=start_of_packet;
uint read_length, multi_byte_packet=0;
if (net->remain_in_buf)
{
uchar *pos = net->buff + net->buf_length - net->remain_in_buf;
if (net->remain_in_buf >= 4)
{
net->length = uint3korr(pos);
if (net->length <= net->remain_in_buf - 4)
{
/* We have a full packet */
len=net->length;
net->remain_in_buf -= net->length + 4;
net->read_pos=pos + 4;
break; /* We have a full packet */
}
}
/* Move data down to read next data packet after current one */
if (net->buf_length != net->remain_in_buf)
{
memmove(net->buff,pos,net->remain_in_buf);
net->buf_length=net->remain_in_buf;
}
net->where_b=net->buf_length;
/* Restore the character that was overwritten by the end 0 */
net->buff[start_of_packet]=net->save_char;
}
else
{
net->where_b=0;
net->buf_length=0;
/* reuse buffer, as there is noting in it that we need */
buf_length=start_of_packet=first_packet_offset=0;
}
for (;;)
{
ulong packet_len;
if (buf_length - start_of_packet >= NET_HEADER_SIZE)
{
read_length = uint3korr(net->buff+start_of_packet);
if (!read_length)
{
/* End of multi-byte packet */
start_of_packet += NET_HEADER_SIZE;
break;
}
if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
{
if (multi_byte_packet)
{
/* Remove packet header for second packet */
memmove(net->buff + first_packet_offset + start_of_packet,
net->buff + first_packet_offset + start_of_packet +
NET_HEADER_SIZE,
buf_length - start_of_packet);
start_of_packet += read_length;
buf_length -= NET_HEADER_SIZE;
}
else
start_of_packet+= read_length + NET_HEADER_SIZE;
if (read_length != MAX_THREE_BYTES) /* last package */
{
multi_byte_packet= 0; // No last zero length packet
break;
}
multi_byte_packet= NET_HEADER_SIZE;
/* Move data down to read next data packet after current one */
if (first_packet_offset)
{
memmove(net->buff,net->buff+first_packet_offset,
buf_length-first_packet_offset);
buf_length-=first_packet_offset;
start_of_packet -= first_packet_offset;
first_packet_offset=0;
}
continue;
}
}
/* Move data down to read next data packet after current one */
if (first_packet_offset)
{
memmove(net->buff,net->buff+first_packet_offset,
buf_length-first_packet_offset);
buf_length-=first_packet_offset;
start_of_packet -= first_packet_offset;
first_packet_offset=0;
}
net->where_b=buf_length;
if ((packet_len = my_real_read(net,&complen)) == packet_error)
return packet_error;
if (my_uncompress((byte*) net->buff + net->where_b, &packet_len,
&complen))
{
net->error=2; /* caller will close socket */
#ifdef MYSQL_SERVER
net->last_errno=ER_NET_UNCOMPRESS_ERROR;
#endif
return packet_error;
}
buf_length+=packet_len;
}
if ((len = my_real_read(net,&complen)) == packet_error)
break;
if (my_uncompress((byte*) net->buff + net->where_b, &len, &complen))
{
len= packet_error;
net->error=2; /* caller will close socket */
#ifdef MYSQL_SERVER
net->last_errno=ER_NET_UNCOMPRESS_ERROR;
#endif
break;
}
net->buf_length+=len;
net->remain_in_buf+=len;
}
if (len != packet_error)
{
net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;
net->buf_length= buf_length;
net->remain_in_buf= buf_length - start_of_packet;
len = ((uint) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
multi_byte_packet);
net->save_char= net->read_pos[len]; /* Must be saved */
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
}
#endif /* HAVE_COMPRESS */
return len;
#endif
}

View File

@ -177,19 +177,19 @@
"Can't write, because of unique constraint, to table '%-.64s'",
"BLOB column '%-.64s' used in key specification without a key length",
"All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead",
"Result consisted of more than one row",
"Tulemis on rohkem kui <20>ks kirje",
"This table type requires a primary key",
"Antud MySQL ei ole kompileeritud RAID-i toega",
"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
"Key '%-.64s' doesn't exist in table '%-.64s'",
"Can't open table",
"The handler for the table doesn't support check/repair",
"You are not allowed to execute this command in a transaction",
"Got error %d during COMMIT",
"Got error %d during ROLLBACK",
"Got error %d during FLUSH_LOGS",
"Got error %d during CHECKPOINT",
"Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
"Ei suuda tabelit avada",
"See tabelit<69><74>p ei toeta k<>ske CHECK/REPAIR",
"Puudub <20>igus selle transaktsioonik<69>su andmiseks",
"Sain vea %d COMMIT k<>su t<>itmisel",
"Sain vea %d ROLLBACK k<>su t<>itmisel",
"Sain vea %d FLUSH_LOGS k<>su t<>itmisel",
"Sain vea %d CHECKPOINT k<>su t<>itmisel",
"<EFBFBD>hendus %ld katkestatud andmebaas: '%-.64s' kasutaja: '%-.32s' masin: `%-.64s' (%-.64s)",
"The handler for the table does not support binary table dump",
"Binlog closed while trying to FLUSH MASTER",
"Failed rebuilding the index of dumped table '%-.64s'",
@ -198,9 +198,9 @@
"Net error writing to master",
"Can't find FULLTEXT index matching the column list",
"Can't execute the given command because you have active locked tables or an active transaction",
"Unknown system variable '%-.64'",
"Table '%-.64s' is marked as crashed and should be repaired",
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
"Tundmatu s<EFBFBD>steemne muutja '%-.64'",
"Tabel '%-.64s' on m<>rgitud vigaseks ja tuleb parandada",
"Tabel '%-.64s' on m<>rgitud vigaseks ja viimane (automaatne?) parandamiskatse eba<62>nnestus",
"Warning: Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",

View File

@ -111,74 +111,71 @@ static void check_unused(void)
#define check_unused()
#endif
int list_open_tables(THD *thd,List<char> *tables, const char *db,
const char *wild)
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
{
int result = 0;
uint col_access=thd->col_access;
OPEN_TABLE_LIST **start_list, *open_list;
TABLE_LIST table_list;
char name[NAME_LEN*2];
DBUG_ENTER("list_open_tables");
VOID(pthread_mutex_lock(&LOCK_open));
bzero((char*) &table_list,sizeof(table_list));
start_list= &open_list;
open_list=0;
for (uint idx=0 ; result == 0 && idx < open_cache.records; idx++)
{
OPEN_TABLE_LIST *table;
TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
if ((!entry->real_name) || strcmp(entry->table_cache_key,db))
continue;
if (wild && wild[0] && wild_compare(entry->real_name,wild))
continue;
if (db && !(col_access & TABLE_ACLS))
{
table_list.db= (char*) db;
table_list.real_name= entry->real_name;/*real name*/
table_list.grant.privilege=col_access;
if (check_grant(thd,TABLE_ACLS,&table_list,1))
continue;
}
/* need to check if he have't already listed it */
List_iterator<char> it(*tables);
char *table_name;
int check = 0;
while (check == 0 && (table_name=it++))
if ((!entry->real_name))
continue; // Shouldn't happen
if (wild)
{
if (!strcmp(table_name,entry->real_name))
check++;
strxmov(name,entry->table_cache_key,".",entry->real_name,NullS);
if (wild_compare(name,wild))
continue;
}
if (check)
/* Check if user has SELECT privilege for any column in the table */
table_list.db= (char*) entry->table_cache_key;
table_list.real_name= entry->real_name;
table_list.grant.privilege=0;
if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list))
continue;
if (tables->push_back(thd->strdup(entry->real_name)))
/* need to check if we haven't already listed it */
for (table= open_list ; table ; table=table->next)
{
result = -1;
if (!strcmp(table->table,entry->real_name) &&
!strcmp(table->db,entry->table_cache_key))
{
if (entry->in_use)
table->in_use++;
if (entry->locked_by_name)
table->locked++;
break;
}
}
if (table)
continue;
if (!(*start_list = (OPEN_TABLE_LIST *)
sql_alloc(sizeof(OPEN_TABLE_LIST)+entry->key_length)))
{
open_list=0; // Out of memory
break;
}
(*start_list)->table=(strmov((*start_list)->db=(char*) ((*start_list)+1),
entry->table_cache_key)+1,
entry->real_name);
(*start_list)->in_use= entry->in_use ? 1 : 0;
(*start_list)->locked= entry->locked_by_name ? 1 : 0;
start_list= &(*start_list)->next;
}
VOID(pthread_mutex_unlock(&LOCK_open));
DBUG_RETURN(result);
}
char*
query_table_status(THD *thd,const char *db,const char *table_name)
{
int cached = 0, in_use = 0;
char info[256];
for (uint idx=0 ; idx < open_cache.records; idx++)
{
TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
if (strcmp(entry->table_cache_key,db) ||
strcmp(entry->real_name,table_name))
continue;
cached++;
if (entry->in_use)
in_use++;
}
sprintf(info, "cached=%d, in_use=%d", cached, in_use);
return thd->strdup(info);
DBUG_RETURN(open_list);
}
@ -258,7 +255,7 @@ send_fields(THD *thd,List<Item> &list,uint flag)
if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length()))
break; /* purecov: inspected */
}
send_eof(&thd->net,(test_flags & TEST_MIT_THREAD) ? 0: 1);
send_eof(&thd->net);
return 0;
err:
send_error(&thd->net,ER_OUT_OF_RESOURCES); /* purecov: inspected */

View File

@ -119,8 +119,13 @@ int generate_table(THD *thd, TABLE_LIST *table_list, TABLE *locked_table)
}
int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
thr_lock_type lock_type, ulong options)
int mysql_delete(THD *thd,
TABLE_LIST *table_list,
COND *conds,
ORDER *order,
ha_rows limit,
thr_lock_type lock_type,
ulong options)
{
int error;
TABLE *table;
@ -191,8 +196,33 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
}
(void) table->file->extra(HA_EXTRA_NO_READCHECK);
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_QUICK);
init_read_record(&info,thd,table,select,-1,1);
(void) table->file->extra(HA_EXTRA_QUICK);
if (order)
{
uint length;
SORT_FIELD *sortorder;
TABLE_LIST tables;
List<Item> fields;
List<Item> all_fields;
bzero((char*) &tables,sizeof(tables));
tables.table = table;
table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
if (setup_order(thd, &tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
(table->found_records = filesort(&table, sortorder, length,
(SQL_SELECT *) 0, 0L, HA_POS_ERROR))
== HA_POS_ERROR)
{
delete select;
DBUG_RETURN(-1); // This will force out message
}
}
init_read_record(&info,thd,table,select,1,1);
ulong deleted=0L;
thd->proc_info="updating";
while (!(error=info.read_record(&info)) && !thd->killed)
@ -218,9 +248,10 @@ int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
}
thd->proc_info="end";
end_read_record(&info);
/* if (order) free_io_cache(table); */ /* QQ Should not be needed */
(void) table->file->extra(HA_EXTRA_READCHECK);
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_NORMAL);
(void) table->file->extra(HA_EXTRA_NORMAL);
using_transactions=table->file->has_transactions();
if (deleted && (error <= 0 || !using_transactions))
{

View File

@ -196,7 +196,7 @@ static int find_keyword(LEX *lex, uint len, bool function)
/* make a copy of token before ptr and set yytoklen */
static inline LEX_STRING get_token(LEX *lex,uint length)
LEX_STRING get_token(LEX *lex,uint length)
{
LEX_STRING tmp;
yyUnget(); // ptr points now after last token char
@ -509,6 +509,8 @@ int yylex(void *arg)
yySkip(); // next state does a unget
}
yylval->lex_str=get_token(lex,length);
if (lex->convert_set)
lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
return(IDENT);
case STATE_IDENT_SEP: // Found ident and now '.'
@ -597,6 +599,8 @@ int yylex(void *arg)
case STATE_FOUND_IDENT: // Complete ident
yylval->lex_str=get_token(lex,yyLength());
if (lex->convert_set)
lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
return(IDENT);
case STATE_USER_VARIABLE_DELIMITER:
@ -604,6 +608,8 @@ int yylex(void *arg)
while ((c=yyGet()) && state_map[c] != STATE_USER_VARIABLE_DELIMITER &&
c != (uchar) NAMES_SEP_CHAR) ;
yylval->lex_str=get_token(lex,yyLength());
if (lex->convert_set)
lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
if (state_map[c] == STATE_USER_VARIABLE_DELIMITER)
yySkip(); // Skipp end `
return(IDENT);

View File

@ -14,6 +14,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef EMBEDDED_LIBRARY
#define net_read_timeout net_read_timeout1
#define net_write_timeout net_write_timeout1
#endif
#include "mysql_priv.h"
#include "sql_acl.h"
@ -26,7 +30,6 @@
#define SCRAMBLE_LENGTH 8
extern int yyparse(void);
extern "C" pthread_mutex_t THR_LOCK_keycache;
#ifdef SOLARIS
@ -36,7 +39,6 @@ extern "C" int gethostname(char *name, int namelen);
static int check_for_max_user_connections(const char *user, int u_length,
const char *host);
static void decrease_user_connections(const char *user, const char *host);
static bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
static bool check_dup(THD *thd,const char *db,const char *name,
@ -701,19 +703,14 @@ err:
}
/* Execute one command from socket (query or simple command) */
bool do_command(THD *thd)
{
char *packet;
uint old_timeout,packet_length;
bool error=0;
NET *net;
enum enum_server_command command;
// commands which will always take a long time should be marked with
// this so that they will not get logged to the slow query log
bool slow_command=FALSE;
DBUG_ENTER("do_command");
net= &thd->net;
@ -740,7 +737,21 @@ bool do_command(THD *thd)
vio_description(net->vio), command,
command_name[command]));
}
net->timeout=old_timeout; /* Timeout */
net->timeout=old_timeout; // Timeout for writing
DBUG_RETURN(dispatch_command(command,thd, packet+1, packet_length));
}
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length)
{
NET *net= &thd->net;
bool error=0;
// commands which will always take a long time should be marked with
// this so that they will not get logged to the slow query log
bool slow_command=FALSE;
DBUG_ENTER("dispatch_command");
thd->command=command;
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id=query_id;
@ -750,22 +761,21 @@ bool do_command(THD *thd)
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->set_time();
thd->lex.options=0; // We store status here
switch(command) {
switch (command) {
case COM_INIT_DB:
if (!mysql_change_db(thd,packet+1))
if (!mysql_change_db(thd,packet))
mysql_log.write(thd,command,"%s",thd->db);
break;
case COM_TABLE_DUMP:
{
slow_command = TRUE;
char* data = packet + 1;
uint db_len = *data;
uint tbl_len = *(data + db_len + 1);
uint db_len = *(uchar*)packet;
uint tbl_len = *(uchar*)(packet + db_len + 1);
char* db = sql_alloc(db_len + tbl_len + 2);
memcpy(db, data + 1, db_len);
memcpy(db, packet + 1, db_len);
char* tbl_name = db + db_len;
*tbl_name++ = 0;
memcpy(tbl_name, data + db_len + 2, tbl_len);
memcpy(tbl_name, packet + db_len + 2, tbl_len);
tbl_name[tbl_len] = 0;
if(mysql_table_dump(thd, db, tbl_name, -1))
send_error(&thd->net); // dump to NET
@ -774,7 +784,7 @@ bool do_command(THD *thd)
}
case COM_CHANGE_USER:
{
char *user= (char*) packet+1;
char *user= (char*) packet;
char *passwd= strend(user)+1;
char *db= strend(passwd)+1;
@ -810,7 +820,7 @@ bool do_command(THD *thd)
case COM_QUERY:
{
char *pos=packet+packet_length; // Point at end null
char *pos=packet-1+packet_length; // Point at end null
/* Remove garage at end of query */
while (packet_length > 0 && pos[-1] == ';')
{
@ -818,7 +828,7 @@ bool do_command(THD *thd)
packet_length--;
}
*pos=0;
if (!(thd->query= (char*) thd->memdup((gptr) (packet+1),packet_length)))
if (!(thd->query= (char*) thd->memdup((gptr) (packet),packet_length)))
break;
thd->packet.shrink(net_buffer_length); // Reclaim some memory
if (!(specialflag & SPECIAL_NO_PRIOR))
@ -846,8 +856,8 @@ bool do_command(THD *thd)
break;
}
thd->free_list=0;
table_list.name=table_list.real_name=thd->strdup(packet+1);
thd->query=fields=thd->strdup(strend(packet+1)+1);
table_list.name=table_list.real_name=thd->strdup(packet);
thd->query=fields=thd->strdup(strend(packet)+1);
mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
remove_escape(table_list.real_name); // This can't have wildcards
@ -869,7 +879,7 @@ bool do_command(THD *thd)
case COM_CREATE_DB:
{
char *db=thd->strdup(packet+1);
char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !stripp_sp(db) || check_db_name(db))
{
@ -878,13 +888,13 @@ bool do_command(THD *thd)
}
if (check_access(thd,CREATE_ACL,db,0,1))
break;
mysql_log.write(thd,command,packet+1);
mysql_log.write(thd,command,packet);
mysql_create_db(thd,db,0);
break;
}
case COM_DROP_DB:
{
char *db=thd->strdup(packet+1);
char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !stripp_sp(db) || check_db_name(db))
{
@ -907,13 +917,13 @@ bool do_command(THD *thd)
ulong pos;
ushort flags;
uint32 slave_server_id;
pos = uint4korr(packet + 1);
flags = uint2korr(packet + 5);
pos = uint4korr(packet);
flags = uint2korr(packet + 4);
pthread_mutex_lock(&LOCK_server_id);
kill_zombie_dump_threads(slave_server_id = uint4korr(packet+7));
kill_zombie_dump_threads(slave_server_id = uint4korr(packet+6));
thd->server_id = slave_server_id;
pthread_mutex_unlock(&LOCK_server_id);
mysql_binlog_send(thd, thd->strdup(packet + 11), pos, flags);
mysql_binlog_send(thd, thd->strdup(packet + 10), pos, flags);
// fake COM_QUIT -- if we get here, the thread needs to terminate
error = TRUE;
net->error = 0;
@ -921,7 +931,7 @@ bool do_command(THD *thd)
}
case COM_REFRESH:
{
uint options=(uchar) packet[1];
uint options=(uchar) packet[0];
if (check_access(thd,RELOAD_ACL,any_db))
break;
mysql_log.write(thd,command,NullS);
@ -980,7 +990,7 @@ bool do_command(THD *thd)
break;
case COM_PROCESS_KILL:
{
ulong id=(ulong) uint4korr(packet+1);
ulong id=(ulong) uint4korr(packet);
kill_one_thread(thd,id);
break;
}
@ -1508,6 +1518,7 @@ mysql_execute_command(void)
lex->item_list,
lex->value_list,
lex->where,
(ORDER *) lex->order_list.first,
lex->select_limit,
lex->duplicates,
lex->lock_option);
@ -1615,8 +1626,8 @@ mysql_execute_command(void)
if (lex->sql_command == SQLCOM_TRUNCATE && end_active_trans(thd))
res= -1;
else
res = mysql_delete(thd,tables,lex->where,lex->select_limit,
lex->lock_option, lex->options);
res = mysql_delete(thd,tables, lex->where, (ORDER*)lex->order_list.first,
lex->select_limit, lex->lock_option, lex->options);
break;
}
case SQLCOM_DROP_TABLE:
@ -1679,7 +1690,6 @@ mysql_execute_command(void)
#endif
case SQLCOM_SHOW_TABLES:
/* FALL THROUGH */
case SQLCOM_SHOW_OPEN_TABLES:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
@ -1700,18 +1710,18 @@ mysql_execute_command(void)
if (check_access(thd,SELECT_ACL,db,&thd->col_access))
goto error; /* purecov: inspected */
/* grant is checked in mysqld_show_tables */
if (lex->sql_command == SQLCOM_SHOW_OPEN_TABLES)
res= mysqld_show_open_tables(thd,db,
(lex->wild ? lex->wild->ptr() : NullS));
else if (lex->options & SELECT_DESCRIBE)
if (lex->options & SELECT_DESCRIBE)
res= mysqld_extend_show_tables(thd,db,
(lex->wild ? lex->wild->ptr() : NullS));
(lex->wild ? lex->wild->ptr() : NullS));
else
res= mysqld_show_tables(thd,db,
(lex->wild ? lex->wild->ptr() : NullS));
break;
}
#endif
case SQLCOM_SHOW_OPEN_TABLES:
res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
break;
case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
@ -2124,7 +2134,7 @@ bool check_process_priv(THD *thd)
** in the table list for GRANT checking
*/
static bool
bool
check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
{
uint found=0,found_access=0;
@ -2150,10 +2160,8 @@ check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
return TRUE; // Access denied
}
if (grant_option)
{
want_access &= ~EXTRA_ACL; // Remove SHOW attribute
return check_grant(thd,want_access,org_tables);
}
return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
test(want_access & EXTRA_ACL));
return FALSE;
}

View File

@ -81,7 +81,7 @@ mysqld_show_dbs(THD *thd,const char *wild)
(grant_option && !check_grant_db(thd, file_name)))
{
thd->packet.length(0);
net_store_data(&thd->packet,file_name);
net_store_data(&thd->packet, thd->convert_set, file_name);
if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
thd->packet.length()))
DBUG_RETURN(-1);
@ -95,39 +95,34 @@ mysqld_show_dbs(THD *thd,const char *wild)
** List all open tables in a database
***************************************************************************/
int mysqld_show_open_tables(THD *thd,const char *db,const char *wild)
int mysqld_show_open_tables(THD *thd,const char *wild)
{
Item_string *field=new Item_string("",0);
List<Item> field_list;
char *end,*table_name;
List<char> tables;
OPEN_TABLE_LIST *open_list;
CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show_open_tables");
field->name=(char*) thd->alloc(20+(uint) strlen(db)+(wild ? (uint) strlen(wild)+4:0));
end=strxmov(field->name,"Open_tables_in_",db,NullS);
if (wild && wild[0])
strxmov(end," (",wild,")",NullS);
field->max_length=NAME_LEN;
field_list.push_back(field);
field_list.push_back(new Item_empty_string("Comment",80));
field_list.push_back(new Item_empty_string("Database",NAME_LEN));
field_list.push_back(new Item_empty_string("Table",NAME_LEN));
field_list.push_back(new Item_int("In_use",0, 4));
field_list.push_back(new Item_int("Name_locked",0, 4));
if (send_fields(thd,field_list,1))
DBUG_RETURN(1);
if (list_open_tables(thd,&tables,db,wild))
if (!(open_list=list_open_tables(thd,wild)))
DBUG_RETURN(-1);
List_iterator<char> it(tables);
while ((table_name=it++))
for ( ; open_list ; open_list=open_list->next)
{
thd->packet.length(0);
net_store_data(&thd->packet,table_name);
net_store_data(&thd->packet,query_table_status(thd,db,table_name));
net_store_data(&thd->packet,convert, open_list->db);
net_store_data(&thd->packet,convert, open_list->table);
net_store_data(&thd->packet,open_list->in_use);
net_store_data(&thd->packet,open_list->locked);
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
DBUG_RETURN(-1);
}
send_eof(&thd->net);
DBUG_RETURN(0);
}
@ -162,7 +157,7 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild)
while ((file_name=it++))
{
thd->packet.length(0);
net_store_data(&thd->packet,file_name);
net_store_data(&thd->packet, thd->convert_set, file_name);
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
DBUG_RETURN(-1);
}
@ -248,6 +243,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
char *file_name;
TABLE *table;
String *packet= &thd->packet;
CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_extend_show_tables");
(void) sprintf(path,"%s/%s",mysql_data_home,db);
@ -293,14 +289,14 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
TABLE_LIST table_list;
bzero((char*) &table_list,sizeof(table_list));
packet->length(0);
net_store_data(packet,file_name);
net_store_data(packet,convert, file_name);
table_list.db=(char*) db;
table_list.real_name=table_list.name=file_name;
if (!(table = open_ltable(thd, &table_list, TL_READ)))
{
for (uint i=0 ; i < field_list.elements ; i++)
net_store_null(packet);
net_store_data(packet,thd->net.last_error);
net_store_data(packet,convert, thd->net.last_error);
thd->net.last_error[0]=0;
}
else
@ -308,8 +304,8 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
struct tm tm_tmp;
handler *file=table->file;
file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
net_store_data(packet, file->table_type());
net_store_data(packet,
net_store_data(packet, convert, file->table_type());
net_store_data(packet, convert,
(table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
"Dynamic" :
(table->db_options_in_use & HA_OPTION_COMPRESS_RECORD)
@ -390,7 +386,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE);
ptr=strmov(ptr,buff);
}
net_store_data(packet, option_buff+1,
net_store_data(packet, convert, option_buff+1,
(ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1));
}
{
@ -422,6 +418,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
TABLE *table;
handler *file;
char tmp[MAX_FIELD_WIDTH];
CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show_fields");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->real_name));
@ -476,18 +473,18 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
bool null_default_value=0;
packet->length(0);
net_store_data(packet,field->field_name);
net_store_data(packet,convert,field->field_name);
field->sql_type(type);
net_store_data(packet,type.ptr(),type.length());
net_store_data(packet,convert,type.ptr(),type.length());
pos=(byte*) ((flags & NOT_NULL_FLAG) &&
field->type() != FIELD_TYPE_TIMESTAMP ?
"" : "YES");
net_store_data(packet,(const char*) pos);
net_store_data(packet,convert,(const char*) pos);
pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
(field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
(field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
net_store_data(packet,(char*) pos);
net_store_data(packet,convert,(char*) pos);
if (field->type() == FIELD_TYPE_TIMESTAMP ||
field->unireg_check == Field::NEXT_NUMBER)
@ -496,17 +493,17 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
{ // Not null by default
type.set(tmp,sizeof(tmp));
field->val_str(&type,&type);
net_store_data(packet,type.ptr(),type.length());
net_store_data(packet,convert,type.ptr(),type.length());
}
else if (field->maybe_null() || null_default_value)
net_store_null(packet); // Null as default
else
net_store_data(packet,tmp,0);
net_store_data(packet,convert,tmp,0);
char *end=tmp;
if (field->unireg_check == Field::NEXT_NUMBER)
end=strmov(tmp,"auto_increment");
net_store_data(packet,tmp,(uint) (end-tmp));
net_store_data(packet,convert,tmp,(uint) (end-tmp));
if (verbose)
{
@ -521,7 +518,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
end=strmov(end,grant_types.type_names[bitnr]);
}
}
net_store_data(packet,tmp+1,end == tmp ? 0 : (uint) (end-tmp-1));
net_store_data(packet,convert, tmp+1,end == tmp ? 0 : (uint) (end-tmp-1));
}
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_RETURN(1);
@ -536,6 +533,7 @@ int
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show_create");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->real_name));
@ -557,7 +555,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
String *packet = &thd->packet;
{
packet->length(0);
net_store_data(packet, table->table_name);
net_store_data(packet,convert, table->table_name);
// a hack - we need to reserve some space for the length before
// we know what it is - let's assume that the length of create table
// statement will fit into 3 bytes ( 16 MB max :-) )
@ -614,6 +612,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
char buff[256];
CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show_keys");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->real_name));
@ -655,16 +654,18 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
{
packet->length(0);
net_store_data(packet,table->table_name);
net_store_data(packet,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1);
net_store_data(packet,key_info->name);
net_store_data(packet,convert,table->table_name);
net_store_data(packet,convert,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1);
net_store_data(packet,convert,key_info->name);
end=int10_to_str((long) (j+1),(char*) buff,10);
net_store_data(packet,buff,(uint) (end-buff));
net_store_data(packet,key_part->field ? key_part->field->field_name :
net_store_data(packet,convert,buff,(uint) (end-buff));
net_store_data(packet,convert,
key_part->field ? key_part->field->field_name :
"?unknown field?");
if (table->file->option_flag() & HA_READ_ORDER)
net_store_data(packet,((key_part->key_part_flag & HA_REVERSE_SORT)
? "D" : "A"), 1);
net_store_data(packet,convert,
((key_part->key_part_flag & HA_REVERSE_SORT) ?
"D" : "A"), 1);
else
net_store_null(packet); /* purecov: inspected */
KEY *key=table->key_info+i;
@ -672,7 +673,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
{
ulong records=(table->file->records / key->rec_per_key[j]);
end=int10_to_str((long) records, buff, 10);
net_store_data(packet,buff,(uint) (end-buff));
net_store_data(packet,convert,buff,(uint) (end-buff));
}
else
net_store_null(packet);
@ -681,12 +682,13 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
table->field[key_part->fieldnr-1]->key_length())
{
end=int10_to_str((long) key_part->length, buff,10); /* purecov: inspected */
net_store_data(packet,buff,(uint) (end-buff)); /* purecov: inspected */
net_store_data(packet,convert,buff,(uint) (end-buff)); /* purecov: inspected */
}
else
net_store_null(packet);
net_store_null(packet); // No pack_information yet
net_store_data(packet,key_info->flags & HA_FULLTEXT ? "FULLTEXT":"");
net_store_data(packet,convert,
key_info->flags & HA_FULLTEXT ? "FULLTEXT":"");
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_RETURN(1); /* purecov: inspected */
}
@ -731,15 +733,18 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
int
mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
{
CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_dump_create_info");
DBUG_PRINT("enter",("table: %s",table->real_name));
String* packet = &thd->packet;
packet->length(0);
if(store_create_info(thd,table,packet))
if (store_create_info(thd,table,packet))
DBUG_RETURN(-1);
if(fd < 0)
if (convert)
convert->convert((char*) packet->ptr(), packet->length());
if (fd < 0)
{
if(my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
DBUG_RETURN(-1);
@ -950,6 +955,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
List<Item> field_list;
I_List<thread_info> thread_infos;
ulong max_query_length= verbose ? max_allowed_packet : PROCESS_LIST_WIDTH;
CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_list_processes");
field_list.push_back(new Item_int("Id",0,7));
@ -1033,28 +1039,28 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
char buff[20],*end;
packet->length(0);
end=int10_to_str((long) thd_info->thread_id, buff,10);
net_store_data(packet,buff,(uint) (end-buff));
net_store_data(packet,thd_info->user);
net_store_data(packet,thd_info->host);
net_store_data(packet,convert,buff,(uint) (end-buff));
net_store_data(packet,convert,thd_info->user);
net_store_data(packet,convert,thd_info->host);
if (thd_info->db)
net_store_data(packet,thd_info->db);
net_store_data(packet,convert,thd_info->db);
else
net_store_null(packet);
if (thd_info->proc_info)
net_store_data(packet,thd_info->proc_info);
net_store_data(packet,convert,thd_info->proc_info);
else
net_store_data(packet,command_name[thd_info->command]);
net_store_data(packet,convert,command_name[thd_info->command]);
if (thd_info->start_time)
net_store_data(packet,(uint32)
(time((time_t*) 0) - thd_info->start_time));
net_store_data(packet,
(uint32) (time((time_t*) 0) - thd_info->start_time));
else
net_store_null(packet);
if (thd_info->state_info)
net_store_data(packet,thd_info->state_info);
net_store_data(packet,convert,thd_info->state_info);
else
net_store_null(packet);
if (thd_info->query)
net_store_data(packet,thd_info->query);
net_store_data(packet,convert,thd_info->query);
else
net_store_null(packet);
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
@ -1076,6 +1082,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
char buff[8192];
String packet2(buff,sizeof(buff));
List<Item> field_list;
CONVERT *convert=thd->convert_set;
DBUG_ENTER("mysqld_show");
field_list.push_back(new Item_empty_string("Variable_name",30));
field_list.push_back(new Item_empty_string("Value",256));
@ -1089,7 +1096,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
if (!(wild && wild[0] && wild_compare(variables[i].name,wild)))
{
packet2.length(0);
net_store_data(&packet2,variables[i].name);
net_store_data(&packet2,convert,variables[i].name);
switch (variables[i].type){
case SHOW_LONG:
case SHOW_LONG_CONST:
@ -1116,7 +1123,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
break;
}
case SHOW_CHAR:
net_store_data(&packet2,variables[i].value);
net_store_data(&packet2,convert, variables[i].value);
break;
case SHOW_STARTTIME:
net_store_data(&packet2,(uint32) (thd->query_start() - start_time));
@ -1130,7 +1137,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
case SHOW_CHAR_PTR:
{
char *value= *(char**) variables[i].value;
net_store_data(&packet2,value ? value : "");
net_store_data(&packet2,convert, value ? value : "");
break;
}
}

View File

@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
@ -40,8 +40,12 @@ static bool compare_record(TABLE *table, ulong query_id)
}
int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
List<Item> &values, COND *conds,
int mysql_update(THD *thd,
TABLE_LIST *table_list,
List<Item> &fields,
List<Item> &values,
COND *conds,
ORDER *order,
ha_rows limit,
enum enum_duplicates handle_duplicates,
thr_lock_type lock_type)
@ -163,6 +167,32 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
if (order)
{
uint length;
SORT_FIELD *sortorder;
TABLE_LIST tables;
List<Item> fields;
List<Item> all_fields;
bzero((char*) &tables,sizeof(tables));
tables.table = table;
table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
if (setup_order(thd, &tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
(table->found_records = filesort(&table, sortorder, length,
(SQL_SELECT *) 0, 0L, HA_POS_ERROR))
== HA_POS_ERROR)
{
delete select;
table->time_stamp=save_time_stamp; // Restore timestamp pointer
DBUG_RETURN(-1);
}
}
init_read_record(&info,thd,table,select,0,1);
thd->proc_info="searching";
@ -180,7 +210,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
}
else
{
if (!(test_flags & 512)) /* For debugging */
if (!(test_flags & 512)) /* For debugging */
{
DBUG_DUMP("record",(char*) table->record[0],table->reclength);
}
@ -202,7 +232,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
select->cond=0;
}
else
{
{
select= new SQL_SELECT;
select->head=table;
}
@ -213,7 +243,7 @@ int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
{
delete select;
table->time_stamp=save_time_stamp; // Restore timestamp pointer
DBUG_RETURN(-1);
DBUG_RETURN(-1);
}
}

View File

@ -72,341 +72,351 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token END_OF_INPUT
%token EQ
%token EQUAL_SYM
%token GE
%token GT_SYM
%token LE
%token LT
%token NE
%token IS
%token SHIFT_LEFT
%token SHIFT_RIGHT
%token SET_VAR
%token AVG_SYM
%token COUNT_SYM
%token MAX_SYM
%token MIN_SYM
%token SUM_SYM
%token STD_SYM
%token ADD
%token ALTER
%token AFTER_SYM
%token ANALYZE_SYM
%token BEGIN_SYM
%token CHANGE
%token COMMENT_SYM
%token COMMIT_SYM
%token CREATE
%token CROSS
%token DELETE_SYM
%token DROP
%token INSERT
%token FLUSH_SYM
%token SELECT_SYM
%token MASTER_SYM
%token REPAIR
%token RESET_SYM
%token PURGE
%token SLAVE
%token START_SYM
%token STOP_SYM
%token TRUNCATE_SYM
%token ROLLBACK_SYM
%token OPTIMIZE
%token SHOW
%token UPDATE_SYM
%token KILL_SYM
%token LOAD
%token LOCK_SYM
%token UNLOCK_SYM
%token ACTION
%token ADD
%token AFTER_SYM
%token AGAINST
%token AGGREGATE_SYM
%token ALL
%token ALTER
%token ANALYZE_SYM
%token AND
%token AS
%token ASC
%token AUTO_INC
%token ATAN
%token AUTOCOMMIT
%token AUTO_INC
%token AVG_ROW_LENGTH
%token BACKUP_SYM
%token AVG_SYM
%token BACKUP_SYM
%token BEGIN_SYM
%token BENCHMARK_SYM
%token BERKELEY_DB_SYM
%token BETWEEN_SYM
%token BIGINT
%token BINARY
%token BIT_AND
%token BIT_OR
%token BIT_SYM
%token BLOB_SYM
%token BOOL_SYM
%token BOTH
%token BY
%token CASCADE
%token CASE_SYM
%token CHANGE
%token CHANGED
%token CHAR_SYM
%token CHECKSUM_SYM
%token CHECK_SYM
%token COMMITTED_SYM
%token COALESCE
%token COLUMNS
%token COLUMN_SYM
%token COMMENT_SYM
%token COMMITTED_SYM
%token COMMIT_SYM
%token COMPRESSED_SYM
%token CONCAT
%token CONCAT_WS
%token CONSTRAINT
%token COUNT_SYM
%token CREATE
%token CROSS
%token CURDATE
%token CURTIME
%token DATABASE
%token DATABASES
%token DATA_SYM
%token DATETIME
%token DATE_ADD_INTERVAL
%token DATE_SUB_INTERVAL
%token DATE_SYM
%token DAY_HOUR_SYM
%token DAY_MINUTE_SYM
%token DAY_SECOND_SYM
%token DAY_SYM
%token DECIMAL_SYM
%token DECODE_SYM
%token DEFAULT
%token DELAYED_SYM
%token DELAY_KEY_WRITE_SYM
%token DELETE_SYM
%token DESC
%token DESCRIBE
%token DISTINCT
%token DOUBLE_SYM
%token DROP
%token DUMPFILE
%token DYNAMIC_SYM
%token ELSE
%token ELT_FUNC
%token ENCLOSED
%token ENCODE_SYM
%token ENCRYPT
%token END
%token ENUM
%token EQ
%token EQUAL_SYM
%token ESCAPED
%token ESCAPE_SYM
%token EXISTS
%token EXPORT_SET
%token EXTENDED_SYM
%token EXTRACT_SYM
%token FAST_SYM
%token FIELD_FUNC
%token FILE_SYM
%token FIRST_SYM
%token FIXED_SYM
%token FLOAT_NUM
%token FLOAT_SYM
%token FLUSH_SYM
%token FOREIGN
%token FORMAT_SYM
%token FOR_SYM
%token FROM
%token FROM_UNIXTIME
%token FULL
%token FULLTEXT_SYM
%token GEMINI_SYM
%token FULLTEXT_SYM
%token FUNC_ARG0
%token FUNC_ARG1
%token FUNC_ARG2
%token FUNC_ARG3
%token GE
%token GEMINI_SPIN_RETRIES
%token GLOBAL_SYM
%token GEMINI_SYM
%token GLOBAL_SYM
%token GRANT
%token GRANTS
%token GREATEST_SYM
%token GROUP
%token GROUP_UNIQUE_USERS
%token GT_SYM
%token HAVING
%token HEAP_SYM
%token HEX_NUM
%token HIGH_PRIORITY
%token HOSTS_SYM
%token HOUR_MINUTE_SYM
%token HOUR_SECOND_SYM
%token HOUR_SYM
%token IDENT
%token IDENTIFIED_SYM
%token IF
%token IGNORE_SYM
%token INDEX
%token INFILE
%token INNER_SYM
%token INNOBASE_SYM
%token INSERT
%token INSERT_ID
%token INTERVAL_SYM
%token INTO
%token INT_SYM
%token IN_SYM
%token ISOLATION
%token IS
%token ISAM_SYM
%token ISOLATION
%token JOIN_SYM
%token KEYS
%token KEY_SYM
%token KILL_SYM
%token LAST_INSERT_ID
%token LE
%token LEADING
%token LEAST_SYM
%token LEVEL_SYM
%token LEFT
%token LEVEL_SYM
%token LEX_HOSTNAME
%token LIKE
%token LIMIT
%token LINES
%token LOAD
%token LOCAL_SYM
%token LOCATE
%token LOCK_SYM
%token LOGS_SYM
%token LONGBLOB
%token LONGTEXT
%token LONG_NUM
%token LONG_SYM
%token LOW_PRIORITY
%token MASTER_HOST_SYM
%token MASTER_USER_SYM
%token MASTER_LOG_FILE_SYM
%token MASTER_LOG_POS_SYM
%token MASTER_PASSWORD_SYM
%token MASTER_PORT_SYM
%token MASTER_CONNECT_RETRY_SYM
%token LT
%token MAKE_SET_SYM
%token MASTER_CONNECT_RETRY_SYM
%token MASTER_HOST_SYM
%token MASTER_LOG_FILE_SYM
%token MASTER_LOG_POS_SYM
%token MASTER_PASSWORD_SYM
%token MASTER_PORT_SYM
%token MASTER_SYM
%token MASTER_USER_SYM
%token MATCH
%token MAX_ROWS
%token MAX_SYM
%token MEDIUMBLOB
%token MEDIUMINT
%token MEDIUMTEXT
%token MEDIUM_SYM
%token MERGE_SYM
%token MINUTE_SECOND_SYM
%token MINUTE_SYM
%token MIN_ROWS
%token MIN_SYM
%token MODE_SYM
%token MODIFY_SYM
%token MONTH_SYM
%token MYISAM_SYM
%token NATIONAL_SYM
%token NATURAL
%token NCHAR_SYM
%token NE
%token NOT
%token NOW_SYM
%token NO_SYM
%token NULL_SYM
%token NUM
%token NUMERIC_SYM
%token ON
%token OPEN_SYM
%token OPTIMIZE
%token OPTION
%token OPTIONALLY
%token OR
%token OR_OR_CONCAT
%token ORDER_SYM
%token OR_OR_CONCAT
%token OUTER
%token OUTFILE
%token DUMPFILE
%token PACK_KEYS_SYM
%token PARTIAL
%token PASSWORD
%token POSITION_SYM
%token PRECISION
%token PRIMARY_SYM
%token PRIVILEGES
%token PROCEDURE
%token PROCESS
%token PROCESSLIST_SYM
%token PURGE
%token QUICK
%token RAID_0_SYM
%token RAID_STRIPED_SYM
%token RAID_TYPE
%token RAID_CHUNKS
%token RAID_CHUNKSIZE
%token RAID_STRIPED_SYM
%token RAID_TYPE
%token RAND
%token READ_SYM
%token REAL
%token REAL_NUM
%token REFERENCES
%token REGEXP
%token RELOAD
%token RENAME
%token REPAIR
%token REPEATABLE_SYM
%token RESTORE_SYM
%token REPLACE
%token RESET_SYM
%token RESTORE_SYM
%token RESTRICT
%token REVOKE
%token RIGHT
%token ROLLBACK_SYM
%token ROUND
%token ROWS_SYM
%token ROW_FORMAT_SYM
%token ROW_SYM
%token SET
%token SECOND_SYM
%token SELECT_SYM
%token SERIALIZABLE_SYM
%token SESSION_SYM
%token SET
%token SET_VAR
%token SHARE_SYM
%token SHIFT_LEFT
%token SHIFT_RIGHT
%token SHOW
%token SHUTDOWN
%token SLAVE
%token SMALLINT
%token SQL_AUTO_IS_NULL
%token SQL_BIG_RESULT
%token SQL_BIG_SELECTS
%token SQL_BIG_TABLES
%token SQL_BUFFER_RESULT
%token SQL_LOG_BIN
%token SQL_LOG_OFF
%token SQL_LOG_UPDATE
%token SQL_LOW_PRIORITY_UPDATES
%token SQL_MAX_JOIN_SIZE
%token SQL_QUOTE_SHOW_CREATE
%token SQL_SAFE_UPDATES
%token SQL_SELECT_LIMIT
%token SQL_SMALL_RESULT
%token SQL_WARNINGS
%token STARTING
%token START_SYM
%token STATUS_SYM
%token STD_SYM
%token STOP_SYM
%token STRAIGHT_JOIN
%token STRING_SYM
%token SUBSTRING
%token SUBSTRING_INDEX
%token SUM_SYM
%token TABLES
%token TABLE_SYM
%token TEMPORARY
%token TERMINATED
%token TEXT_STRING
%token TO_SYM
%token TRAILING
%token TRANSACTION_SYM
%token TYPE_SYM
%token FUNC_ARG0
%token FUNC_ARG1
%token FUNC_ARG2
%token FUNC_ARG3
%token UDF_RETURNS_SYM
%token UDF_SONAME_SYM
%token UDF_SYM
%token UNCOMMITTED_SYM
%token UNION_SYM
%token UNIQUE_SYM
%token USAGE
%token USE_SYM
%token USING
%token VALUES
%token VARIABLES
%token WHERE
%token WITH
%token WRITE_SYM
%token COMPRESSED_SYM
%token BIGINT
%token BLOB_SYM
%token CHAR_SYM
%token CHANGED
%token COALESCE
%token DATETIME
%token DATE_SYM
%token DECIMAL_SYM
%token DOUBLE_SYM
%token ENUM
%token FAST_SYM
%token FLOAT_SYM
%token INT_SYM
%token LIMIT
%token LONGBLOB
%token LONGTEXT
%token MEDIUMBLOB
%token MEDIUMINT
%token MEDIUMTEXT
%token NUMERIC_SYM
%token PRECISION
%token QUICK
%token REAL
%token SMALLINT
%token STRING_SYM
%token TEXT_SYM
%token THEN_SYM
%token TIMESTAMP
%token TIME_SYM
%token TINYBLOB
%token TINYINT
%token TINYTEXT
%token UNSIGNED
%token VARBINARY
%token VARCHAR
%token VARYING
%token ZEROFILL
%token AGAINST
%token ATAN
%token BETWEEN_SYM
%token BIT_AND
%token BIT_OR
%token CASE_SYM
%token CONCAT
%token CONCAT_WS
%token CURDATE
%token CURTIME
%token DATABASE
%token DATE_ADD_INTERVAL
%token DATE_SUB_INTERVAL
%token DAY_HOUR_SYM
%token DAY_MINUTE_SYM
%token DAY_SECOND_SYM
%token DAY_SYM
%token DECODE_SYM
%token ELSE
%token ELT_FUNC
%token ENCODE_SYM
%token ENCRYPT
%token EXPORT_SET
%token EXTRACT_SYM
%token FIELD_FUNC
%token FORMAT_SYM
%token FOR_SYM
%token FROM_UNIXTIME
%token GROUP_UNIQUE_USERS
%token HOUR_MINUTE_SYM
%token HOUR_SECOND_SYM
%token HOUR_SYM
%token IDENTIFIED_SYM
%token IF
%token INSERT_ID
%token INTERVAL_SYM
%token LAST_INSERT_ID
%token LEFT
%token LOCATE
%token MAKE_SET_SYM
%token MINUTE_SECOND_SYM
%token MINUTE_SYM
%token MODE_SYM
%token MODIFY_SYM
%token MONTH_SYM
%token NOW_SYM
%token PASSWORD
%token POSITION_SYM
%token PROCEDURE
%token RAND
%token REPLACE
%token RIGHT
%token ROUND
%token SECOND_SYM
%token SHARE_SYM
%token SUBSTRING
%token SUBSTRING_INDEX
%token TO_SYM
%token TRAILING
%token TRANSACTION_SYM
%token TRIM
%token TRUNCATE_SYM
%token TYPE_SYM
%token UDA_CHAR_SUM
%token UDA_FLOAT_SUM
%token UDA_INT_SUM
%token UDF_CHAR_FUNC
%token UDF_FLOAT_FUNC
%token UDF_INT_FUNC
%token UDF_RETURNS_SYM
%token UDF_SONAME_SYM
%token UDF_SYM
%token UNCOMMITTED_SYM
%token UNION_SYM
%token UNIQUE_SYM
%token UNIQUE_USERS
%token UNIX_TIMESTAMP
%token UNLOCK_SYM
%token UNSIGNED
%token UPDATE_SYM
%token USAGE
%token USER
%token USE_SYM
%token USING
%token VALUES
%token VARBINARY
%token VARCHAR
%token VARIABLES
%token VARYING
%token WEEK_SYM
%token WHEN_SYM
%token WORK_SYM
%token WHERE
%token WITH
%token WORK_SYM
%token WRITE_SYM
%token YEARWEEK
%token YEAR_MONTH_SYM
%token YEAR_SYM
%token YEARWEEK
%token BENCHMARK_SYM
%token END
%token THEN_SYM
%token ZEROFILL
%token SQL_BIG_TABLES
%token SQL_BIG_SELECTS
@ -1240,7 +1250,7 @@ select:
select_options select_item_list select_into select_lock_type
select_into:
/* empty */
limit_clause {}
| select_from
| opt_into select_from
| select_from opt_into
@ -2128,8 +2138,17 @@ values:
/* Update rows in a table */
update:
UPDATE_SYM opt_low_priority opt_ignore table SET update_list where_clause delete_limit_clause
{ Lex->sql_command = SQLCOM_UPDATE; }
UPDATE_SYM opt_low_priority opt_ignore table
SET update_list
where_clause
opt_order_clause
delete_limit_clause
{
Lex->sql_command = SQLCOM_UPDATE;
Lex->order_list.elements=0;
Lex->order_list.first=0;
Lex->order_list.next= (byte**) &Lex->order_list.first;
}
update_list:
update_list ',' simple_ident equal expr
@ -2151,12 +2170,15 @@ opt_low_priority:
delete:
DELETE_SYM
{
Lex->sql_command= SQLCOM_DELETE; Lex->options=0;
{
Lex->sql_command= SQLCOM_DELETE; Lex->options=0;
Lex->lock_option= current_thd->update_lock_default;
}
Lex->order_list.elements=0;
Lex->order_list.first=0;
Lex->order_list.next= (byte**) &Lex->order_list.first;
}
opt_delete_options FROM table
where_clause delete_limit_clause
where_clause opt_order_clause delete_limit_clause
opt_delete_options:
@ -2169,8 +2191,15 @@ opt_delete_option:
truncate:
TRUNCATE_SYM opt_table_sym table
{ Lex->sql_command= SQLCOM_TRUNCATE; Lex->options=0;
Lex->lock_option= current_thd->update_lock_default; }
{
LEX* lex = Lex;
lex->sql_command= SQLCOM_TRUNCATE;
lex->options=0;
lex->order_list.elements=0;
lex->order_list.first=0;
lex->order_list.next= (byte**) &lex->order_list.first;
lex->lock_option= current_thd->update_lock_default; }
opt_table_sym:
/* empty */

View File

@ -143,3 +143,10 @@ typedef struct st_table_list {
bool straight; /* optimize with prev table */
bool updating; /* for replicate-do/ignore table */
} TABLE_LIST;
typedef struct st_open_table_list
{
struct st_open_table_list *next;
char *db,*table;
uint32 in_use,locked;
} OPEN_TABLE_LIST;