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
This commit is contained in:
13
BUILD/compile-pentium-mysqlfs-debug
Executable file
13
BUILD/compile-pentium-mysqlfs-debug
Executable 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"
|
@ -1 +1 @@
|
||||
heikki@donna.mysql.fi
|
||||
monty@work.mysql.com
|
||||
|
17
Makefile.am
17
Makefile.am
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
47
acinclude.m4
47
acinclude.m4
@ -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
|
||||
|
110
client/mysql.cc
110
client/mysql.cc
@ -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[] = {
|
||||
"&", "&",
|
||||
"<", "<",
|
||||
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 :
|
||||
" ") : "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 :
|
||||
" ") : "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);
|
||||
}
|
||||
}
|
||||
|
66
configure.in
66
configure.in
@ -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
38
fs/CorbaFS.idl
Normal 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
93
fs/Makefile.am
Normal 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
58
fs/README
Normal 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
2
fs/RunServer.sh
Executable 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
629
fs/database.c
Normal 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 :
|
||||
" ") : "NULL"));
|
||||
xmlencode(data, cur[i]);
|
||||
tee_fprintf(PAGER, "</%s>\n", (fields[i].name ?
|
||||
(fields[i].name[0] ? fields[i].name :
|
||||
" ") : "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
28
fs/dump.sql
Normal 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
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
153
fs/libmysqlfs.c
Normal 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
81
fs/libmysqlfs.h
Normal 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
5
fs/my.cnf
Normal 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
992
fs/mysqlcorbafs.c
Normal 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 :
|
||||
" ") : "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 :
|
||||
" ") : "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 :
|
||||
" ") : "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
159
fs/mysqlcorbafs.h
Normal 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
92
fs/mysqlcorbafs_test.c
Normal 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
11
fs/mysqlfsck
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
mountpoint=$*
|
||||
|
||||
if [#($mountpoint) -eq "0"];
|
||||
then
|
||||
exit;
|
||||
fi
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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).
|
||||
|
287
libmysql/net.c
287
libmysql/net.c
@ -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;
|
||||
@ -91,21 +104,18 @@ extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
|
||||
#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;
|
||||
@ -153,7 +163,11 @@ static my_bool net_realloc(NET *net, ulong length)
|
||||
return 1;
|
||||
}
|
||||
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
|
||||
if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
|
||||
/* 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
106
libmysqld/Makefile.am
Normal 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
26
libmysqld/README
Normal 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
16
libmysqld/WHITEPAPER
Normal 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
14
libmysqld/copyright
Normal 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
41
libmysqld/lib_load.cc
Normal 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
650
libmysqld/lib_sql.cc
Normal 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
236
libmysqld/lib_vio.c
Normal 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
2299
libmysqld/libmysqld.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
222
myisam/ft_boolean_search.c
Normal 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,¶m); 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
214
myisam/ft_dump.c
Normal 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
191
myisam/ft_nlq_search.c
Normal 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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(¶m->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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
1220
myisam/mi_search.c
1220
myisam/mi_search.c
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
146
myisam/sort.c
146
myisam/sort.c
@ -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,
|
||||
@ -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 */
|
||||
|
@ -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;
|
||||
|
10
mysql-test/r/fulltext_distinct.result
Normal file
10
mysql-test/r/fulltext_distinct.result
Normal 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
|
39
mysql-test/t/fulltext_distinct.test
Normal file
39
mysql-test/t/fulltext_distinct.test
Normal 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
25
pstack/Makefile.am
Normal 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
475
pstack/aout/aout64.h
Normal 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
264
pstack/aout/stab.def
Normal 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
37
pstack/aout/stab_gnu.h
Normal 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
238
pstack/bucomm.c
Normal 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
85
pstack/bucomm.h
Normal 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
58
pstack/budbg.h
Normal 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
3509
pstack/debug.c
Normal file
File diff suppressed because it is too large
Load Diff
798
pstack/debug.h
Normal file
798
pstack/debug.h
Normal 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
90
pstack/demangle.h
Normal 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
266
pstack/filemode.c
Normal 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
7602
pstack/ieee.c
Normal file
File diff suppressed because it is too large
Load Diff
139
pstack/ieee.h
Normal file
139
pstack/ieee.h
Normal 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
180
pstack/libiberty.h
Normal 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
90
pstack/linuxthreads.c
Normal 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
28
pstack/linuxthreads.h
Normal 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
2746
pstack/pstack.c
Normal file
File diff suppressed because it is too large
Load Diff
22
pstack/pstack.h
Normal file
22
pstack/pstack.h
Normal 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
24
pstack/pstacktrace.h
Normal 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
462
pstack/rddbg.c
Normal 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
5082
pstack/stabs.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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 ...
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
|
@ -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__ */
|
||||
#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);
|
||||
@ -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},
|
||||
@ -3633,7 +3649,7 @@ static void get_options(int argc,char **argv)
|
||||
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])
|
||||
|
289
sql/net_serv.cc
289
sql/net_serv.cc
@ -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>
|
||||
@ -91,21 +104,18 @@ extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
|
||||
#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;
|
||||
@ -153,7 +163,11 @@ static my_bool net_realloc(NET *net, ulong length)
|
||||
return 1;
|
||||
}
|
||||
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
|
||||
if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
|
||||
/* 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
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
@ -192,7 +197,32 @@ 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);
|
||||
|
||||
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,6 +248,7 @@ 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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
127
sql/sql_show.cc
127
sql/sql_show.cc
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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";
|
||||
|
||||
|
423
sql/sql_yacc.yy
423
sql/sql_yacc.yy
@ -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
|
||||
@ -2152,11 +2171,14 @@ 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 */
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user