mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Add some examples for using libmysqld, including a hack for running the
mysql test suite. A few minor libmysqld fixes. Add mysql_server_init() and _end() to mysql.cc and mysqltest.c, so they can be linked against libmysqlclient or libmysqld.
This commit is contained in:
@ -400,3 +400,4 @@ vio/test-sslclient
|
|||||||
vio/test-sslserver
|
vio/test-sslserver
|
||||||
vio/viotest-ssl
|
vio/viotest-ssl
|
||||||
tools/mysqlmanager
|
tools/mysqlmanager
|
||||||
|
linked_libmysqldex_sources
|
||||||
|
@ -29,7 +29,8 @@ SUBDIRS = include @docs_dirs@ @readline_dir@ \
|
|||||||
# Relink after clean
|
# Relink after clean
|
||||||
linked_sources = linked_client_sources linked_server_sources \
|
linked_sources = linked_client_sources linked_server_sources \
|
||||||
linked_libmysql_sources linked_libmysql_r_sources \
|
linked_libmysql_sources linked_libmysql_r_sources \
|
||||||
linked_libmysqld_sources linked_include_sources
|
linked_libmysqld_sources linked_libmysqldex_sources \
|
||||||
|
linked_include_sources
|
||||||
|
|
||||||
CLEANFILES = $(linked_sources)
|
CLEANFILES = $(linked_sources)
|
||||||
|
|
||||||
@ -56,6 +57,10 @@ linked_libmysqld_sources:
|
|||||||
cd libmysqld; $(MAKE) link_sources
|
cd libmysqld; $(MAKE) link_sources
|
||||||
echo timestamp > linked_libmysqld_sources
|
echo timestamp > linked_libmysqld_sources
|
||||||
|
|
||||||
|
linked_libmysqldex_sources:
|
||||||
|
cd libmysqld/examples; $(MAKE) link_sources
|
||||||
|
echo timestamp > linked_libmysqldex_sources
|
||||||
|
|
||||||
#avoid recursive make calls in sql directory
|
#avoid recursive make calls in sql directory
|
||||||
linked_server_sources:
|
linked_server_sources:
|
||||||
cd sql; rm -f mini_client_errors.c;@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c
|
cd sql; rm -f mini_client_errors.c;@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c
|
||||||
|
72
acinclude.m4
72
acinclude.m4
@ -1071,42 +1071,42 @@ AC_DEFUN([MYSQL_CHECK_INNODB], [
|
|||||||
dnl Some libs are listed several times, in order for gcc to sort out
|
dnl Some libs are listed several times, in order for gcc to sort out
|
||||||
dnl circular references.
|
dnl circular references.
|
||||||
innodb_libs="\
|
innodb_libs="\
|
||||||
../innobase/usr/libusr.a\
|
$(top_builddir)/innobase/usr/libusr.a\
|
||||||
../innobase/odbc/libodbc.a\
|
$(top_builddir)/innobase/odbc/libodbc.a\
|
||||||
../innobase/srv/libsrv.a\
|
$(top_builddir)/innobase/srv/libsrv.a\
|
||||||
../innobase/que/libque.a\
|
$(top_builddir)/innobase/que/libque.a\
|
||||||
../innobase/srv/libsrv.a\
|
$(top_builddir)/innobase/srv/libsrv.a\
|
||||||
../innobase/dict/libdict.a\
|
$(top_builddir)/innobase/dict/libdict.a\
|
||||||
../innobase/ibuf/libibuf.a\
|
$(top_builddir)/innobase/ibuf/libibuf.a\
|
||||||
../innobase/row/librow.a\
|
$(top_builddir)/innobase/row/librow.a\
|
||||||
../innobase/pars/libpars.a\
|
$(top_builddir)/innobase/pars/libpars.a\
|
||||||
../innobase/btr/libbtr.a\
|
$(top_builddir)/innobase/btr/libbtr.a\
|
||||||
../innobase/trx/libtrx.a\
|
$(top_builddir)/innobase/trx/libtrx.a\
|
||||||
../innobase/read/libread.a\
|
$(top_builddir)/innobase/read/libread.a\
|
||||||
../innobase/usr/libusr.a\
|
$(top_builddir)/innobase/usr/libusr.a\
|
||||||
../innobase/buf/libbuf.a\
|
$(top_builddir)/innobase/buf/libbuf.a\
|
||||||
../innobase/ibuf/libibuf.a\
|
$(top_builddir)/innobase/ibuf/libibuf.a\
|
||||||
../innobase/eval/libeval.a\
|
$(top_builddir)/innobase/eval/libeval.a\
|
||||||
../innobase/log/liblog.a\
|
$(top_builddir)/innobase/log/liblog.a\
|
||||||
../innobase/fsp/libfsp.a\
|
$(top_builddir)/innobase/fsp/libfsp.a\
|
||||||
../innobase/fut/libfut.a\
|
$(top_builddir)/innobase/fut/libfut.a\
|
||||||
../innobase/fil/libfil.a\
|
$(top_builddir)/innobase/fil/libfil.a\
|
||||||
../innobase/lock/liblock.a\
|
$(top_builddir)/innobase/lock/liblock.a\
|
||||||
../innobase/mtr/libmtr.a\
|
$(top_builddir)/innobase/mtr/libmtr.a\
|
||||||
../innobase/page/libpage.a\
|
$(top_builddir)/innobase/page/libpage.a\
|
||||||
../innobase/rem/librem.a\
|
$(top_builddir)/innobase/rem/librem.a\
|
||||||
../innobase/thr/libthr.a\
|
$(top_builddir)/innobase/thr/libthr.a\
|
||||||
../innobase/com/libcom.a\
|
$(top_builddir)/innobase/com/libcom.a\
|
||||||
../innobase/sync/libsync.a\
|
$(top_builddir)/innobase/sync/libsync.a\
|
||||||
../innobase/data/libdata.a\
|
$(top_builddir)/innobase/data/libdata.a\
|
||||||
../innobase/mach/libmach.a\
|
$(top_builddir)/innobase/mach/libmach.a\
|
||||||
../innobase/ha/libha.a\
|
$(top_builddir)/innobase/ha/libha.a\
|
||||||
../innobase/dyn/libdyn.a\
|
$(top_builddir)/innobase/dyn/libdyn.a\
|
||||||
../innobase/mem/libmem.a\
|
$(top_builddir)/innobase/mem/libmem.a\
|
||||||
../innobase/sync/libsync.a\
|
$(top_builddir)/innobase/sync/libsync.a\
|
||||||
../innobase/ut/libut.a\
|
$(top_builddir)/innobase/ut/libut.a\
|
||||||
../innobase/os/libos.a\
|
$(top_builddir)/innobase/os/libos.a\
|
||||||
../innobase/ut/libut.a"
|
$(top_builddir)/innobase/ut/libut.a"
|
||||||
|
|
||||||
AC_CHECK_LIB(rt, aio_read, [innodb_libs="$innodb_libs -lrt"])
|
AC_CHECK_LIB(rt, aio_read, [innodb_libs="$innodb_libs -lrt"])
|
||||||
;;
|
;;
|
||||||
|
@ -248,6 +248,7 @@ static COMMANDS commands[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const char *load_default_groups[]= { "mysql","client",0 };
|
static const char *load_default_groups[]= { "mysql","client",0 };
|
||||||
|
static const char *server_default_groups[]= { "server", "mysql_SERVER", 0 };
|
||||||
|
|
||||||
#ifdef HAVE_READLINE
|
#ifdef HAVE_READLINE
|
||||||
extern "C" void add_history(char *command); /* From readline directory */
|
extern "C" void add_history(char *command); /* From readline directory */
|
||||||
@ -275,6 +276,7 @@ int main(int argc,char *argv[])
|
|||||||
{
|
{
|
||||||
char buff[80];
|
char buff[80];
|
||||||
|
|
||||||
|
mysql_server_init(0, NULL, server_default_groups);
|
||||||
MY_INIT(argv[0]);
|
MY_INIT(argv[0]);
|
||||||
DBUG_ENTER("main");
|
DBUG_ENTER("main");
|
||||||
DBUG_PROCESS(argv[0]);
|
DBUG_PROCESS(argv[0]);
|
||||||
@ -368,6 +370,7 @@ int main(int argc,char *argv[])
|
|||||||
if (opt_outfile)
|
if (opt_outfile)
|
||||||
end_tee();
|
end_tee();
|
||||||
mysql_end(0);
|
mysql_end(0);
|
||||||
|
mysql_server_end();
|
||||||
#ifndef _lint
|
#ifndef _lint
|
||||||
DBUG_RETURN(0); // Keep compiler happy
|
DBUG_RETURN(0); // Keep compiler happy
|
||||||
#endif
|
#endif
|
||||||
@ -377,9 +380,11 @@ sig_handler mysql_end(int sig)
|
|||||||
{
|
{
|
||||||
if (connected)
|
if (connected)
|
||||||
mysql_close(&mysql);
|
mysql_close(&mysql);
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
else
|
else
|
||||||
mysql_ssl_clear(&mysql); /* SSL data structres should be freed
|
mysql_ssl_clear(&mysql); /* SSL data structres should be freed
|
||||||
even if connection was not made */
|
even if connection was not made */
|
||||||
|
#endif
|
||||||
#ifdef HAVE_READLINE
|
#ifdef HAVE_READLINE
|
||||||
if (!status.batch && !quick && !opt_html && !opt_xml)
|
if (!status.batch && !quick && !opt_html && !opt_xml)
|
||||||
{
|
{
|
||||||
@ -2217,9 +2222,11 @@ sql_real_connect(char *host,char *database,char *user,char *password,
|
|||||||
mysql_close(&mysql);
|
mysql_close(&mysql);
|
||||||
connected= 0;
|
connected= 0;
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
else
|
else
|
||||||
mysql_ssl_clear(&mysql); /* SSL data structres should be freed
|
mysql_ssl_clear(&mysql); /* SSL data structres should be freed
|
||||||
even if connection was not made */
|
even if connection was not made */
|
||||||
|
#endif
|
||||||
mysql_init(&mysql);
|
mysql_init(&mysql);
|
||||||
if (opt_connect_timeout)
|
if (opt_connect_timeout)
|
||||||
{
|
{
|
||||||
@ -2571,6 +2578,7 @@ static void mysql_end_timer(ulong start_time,char *buff)
|
|||||||
strmov(strend(buff),")");
|
strmov(strend(buff),")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef EMBEDDED_SERVER
|
||||||
/* Keep sql_string library happy */
|
/* Keep sql_string library happy */
|
||||||
|
|
||||||
gptr sql_alloc(unsigned int Size)
|
gptr sql_alloc(unsigned int Size)
|
||||||
@ -2582,3 +2590,4 @@ void sql_element_free(void *ptr)
|
|||||||
{
|
{
|
||||||
my_free((gptr) ptr,MYF(0));
|
my_free((gptr) ptr,MYF(0));
|
||||||
}
|
}
|
||||||
|
#endif /* EMBEDDED_SERVER */
|
||||||
|
@ -1931,12 +1931,26 @@ static void init_var_hash()
|
|||||||
var_from_env("BIG_TEST", opt_big_test ? "1" : "0");
|
var_from_env("BIG_TEST", opt_big_test ? "1" : "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *embedded_server_args[] = {
|
||||||
|
"", /* XXX: argv[0] is program name - we should fix the API */
|
||||||
|
"--datadir=.",
|
||||||
|
"--language=/home/tim/my/4/sql/share/english",
|
||||||
|
"--skip-innodb",
|
||||||
|
NullS
|
||||||
|
};
|
||||||
|
static const char *embedded_server_groups[] = {
|
||||||
|
"mysql-test-server",
|
||||||
|
NullS
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
struct st_query* q;
|
struct st_query* q;
|
||||||
my_bool require_file=0, q_send_flag=0;
|
my_bool require_file=0, q_send_flag=0;
|
||||||
char save_file[FN_REFLEN];
|
char save_file[FN_REFLEN];
|
||||||
|
mysql_server_init(sizeof(embedded_server_args) / sizeof(char *) - 1,
|
||||||
|
embedded_server_args, embedded_server_groups);
|
||||||
MY_INIT(argv[0]);
|
MY_INIT(argv[0]);
|
||||||
|
|
||||||
save_file[0]=0;
|
save_file[0]=0;
|
||||||
@ -2100,6 +2114,7 @@ int main(int argc, char** argv)
|
|||||||
printf("ok\n");
|
printf("ok\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mysql_server_end();
|
||||||
free_used_memory();
|
free_used_memory();
|
||||||
exit(error ? 1 : 0);
|
exit(error ? 1 : 0);
|
||||||
return error ? 1 : 0; /* Keep compiler happy */
|
return error ? 1 : 0; /* Keep compiler happy */
|
||||||
|
@ -1804,7 +1804,7 @@ AC_ARG_WITH(readline,
|
|||||||
if test "$with_readline" = "yes"
|
if test "$with_readline" = "yes"
|
||||||
then
|
then
|
||||||
readline_dir="readline"
|
readline_dir="readline"
|
||||||
readline_link="../readline/libreadline.a"
|
readline_link="\$(top_builddir)/readline/libreadline.a"
|
||||||
else
|
else
|
||||||
# This requires readline to be in a standard place. Mosty for linux
|
# This requires readline to be in a standard place. Mosty for linux
|
||||||
# there readline may be a shared library.
|
# there readline may be a shared library.
|
||||||
@ -2219,7 +2219,8 @@ AC_OUTPUT(Makefile extra/Makefile mysys/Makefile isam/Makefile \
|
|||||||
bdb/Makefile \
|
bdb/Makefile \
|
||||||
myisam/Makefile myisammrg/Makefile \
|
myisam/Makefile myisammrg/Makefile \
|
||||||
man/Makefile readline/Makefile vio/Makefile \
|
man/Makefile readline/Makefile vio/Makefile \
|
||||||
libmysql_r/Makefile libmysqld/Makefile libmysql/Makefile client/Makefile \
|
libmysql_r/Makefile libmysqld/Makefile libmysqld/examples/Makefile \
|
||||||
|
libmysql/Makefile client/Makefile \
|
||||||
pstack/Makefile sql/Makefile sql/share/Makefile \
|
pstack/Makefile sql/Makefile sql/share/Makefile \
|
||||||
merge/Makefile dbug/Makefile scripts/Makefile \
|
merge/Makefile dbug/Makefile scripts/Makefile \
|
||||||
include/Makefile sql-bench/Makefile tools/Makefile \
|
include/Makefile sql-bench/Makefile tools/Makefile \
|
||||||
|
33
libmysqld/examples/Makefile.am
Normal file
33
libmysqld/examples/Makefile.am
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
bin_PROGRAMS = mysqltest mysql
|
||||||
|
client_sources = $(mysqltest_SOURCES) $(mysql_SOURCES)
|
||||||
|
link_sources:
|
||||||
|
for f in $(client_sources); do \
|
||||||
|
rm -f $(srcdir)/$$f; \
|
||||||
|
@LN_CP_F@ $(srcdir)/../../client/$$f $(srcdir)/$$f; \
|
||||||
|
done;
|
||||||
|
|
||||||
|
DEFS = -DEMBEDDED_SERVER
|
||||||
|
INCLUDES = -I$(top_srcdir)/include $(openssl_includes) \
|
||||||
|
-I$(srcdir) -I$(top_srcdir) -I..
|
||||||
|
LIBS = @LIBS@
|
||||||
|
LDADD = $(top_builddir)/libmysqld/libmysqld.la \
|
||||||
|
$(top_builddir)/isam/libnisam.a \
|
||||||
|
$(top_builddir)/myisam/libmyisam.a \
|
||||||
|
$(top_builddir)/heap/libheap.a \
|
||||||
|
$(top_builddir)/merge/libmerge.a \
|
||||||
|
$(top_builddir)/myisammrg/libmyisammrg.a \
|
||||||
|
@innodb_libs@ @bdb_libs@ \
|
||||||
|
$(top_builddir)/mysys/libmysys.a \
|
||||||
|
$(top_builddir)/strings/libmystrings.a \
|
||||||
|
$(top_builddir)/dbug/libdbug.a \
|
||||||
|
$(top_builddir)/regex/libregex.a
|
||||||
|
|
||||||
|
mysqltest_DEPENDENCIES = ../libmysqld.la
|
||||||
|
mysqltest_SOURCES = mysqltest.c
|
||||||
|
|
||||||
|
mysql_SOURCES = mysql.cc readline.cc sql_string.cc completion_hash.cc \
|
||||||
|
my_readline.h sql_string.h completion_hash.h
|
||||||
|
mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(client_sources)
|
131
libmysqld/examples/test-run
Executable file
131
libmysqld/examples/test-run
Executable file
@ -0,0 +1,131 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
# This is slapped together as a quick way to run the tests and
|
||||||
|
# is not meant for prime time. Please hack at it and submit
|
||||||
|
# changes, though, so we can gradually turn it into something
|
||||||
|
# that will run on all platforms (or incorporate it into the
|
||||||
|
# standard mysql-test-run).
|
||||||
|
|
||||||
|
#test_data_dir=/tmp/mysql-data
|
||||||
|
test_data_dir=../../mysql-test/var/master-data
|
||||||
|
cd "$test_data_dir" || {
|
||||||
|
echo "can't cd to $test_data_dir" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# All paths below must be relative to $test_data_dir
|
||||||
|
#top_builddir=/home/tim/my/4
|
||||||
|
top_builddir=../../..
|
||||||
|
mysql_test_dir=$top_builddir/mysql-test
|
||||||
|
examples=$top_builddir/libmysqld/examples
|
||||||
|
mysqltest=$examples/mysqltest
|
||||||
|
testdir=./test
|
||||||
|
|
||||||
|
gdb=0
|
||||||
|
list=0
|
||||||
|
run=
|
||||||
|
tests=
|
||||||
|
start=
|
||||||
|
|
||||||
|
cr="
|
||||||
|
"
|
||||||
|
er="\b\b\b\b\b\b\b\b"
|
||||||
|
|
||||||
|
usage () {
|
||||||
|
cat <<EOF
|
||||||
|
usage: $0 [-g|-h|-r] [test-name ...]
|
||||||
|
|
||||||
|
-g | --gdb run $mysqltest in gdb
|
||||||
|
-h | --help show this help
|
||||||
|
-l | --list ) list all available tests
|
||||||
|
-r | --run automatically 'run' program in gdb
|
||||||
|
-s t | --start=t start with test t (skip all tests before t)
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while test $# -gt 0
|
||||||
|
do
|
||||||
|
arg=
|
||||||
|
argset=0
|
||||||
|
case "$1" in
|
||||||
|
--?*=* ) arg=`echo "$1" | sed -e 's,^[^=][^=]*=,,'`; argset=1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
-g | --gdb ) gdb=1; shift;;
|
||||||
|
-h | --help | -\? ) usage; exit 0;;
|
||||||
|
-l | --list ) list=1 ; shift ;;
|
||||||
|
-r | --run ) run="${cr}run"; shift;;
|
||||||
|
-s | --start=* )
|
||||||
|
test $argset -eq 0 && { shift; arg="$1"; }
|
||||||
|
start="$arg"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-* ) usage; exit 1;;
|
||||||
|
* ) tests="$tests $1"; shift;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
test -d "$mysql_test_dir/t" -a -d "$mysql_test_dir/r" -a \
|
||||||
|
-f $mysqltest -a -d $testdir || {
|
||||||
|
echo "bad setup (is '$testdir', from '$test_data_dir', missing?)" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
test -n "$tests" ||
|
||||||
|
tests=`/bin/ls -1 "$mysql_test_dir"/t/*.test | grep -v '^.*/rpl[^/]*$' | \
|
||||||
|
sed -e 's,^.*/,,' -e 's,.test$,,'`
|
||||||
|
|
||||||
|
echo "cleaning data directory '$test_data_dir'"
|
||||||
|
rm -f $test_data_dir/ib_* $test_data_dir/ibdata* log.*
|
||||||
|
echo "cleaning test directory '$testdir'"
|
||||||
|
rm -f $testdir/*
|
||||||
|
|
||||||
|
rm -f test-gdbinit
|
||||||
|
|
||||||
|
TZ=GMT-3; export TZ
|
||||||
|
|
||||||
|
skip=1
|
||||||
|
test -z "$start" && skip=0
|
||||||
|
|
||||||
|
for b in $tests
|
||||||
|
do
|
||||||
|
test $list -eq 1 && { echo " $b"; continue; }
|
||||||
|
test $skip -eq 1 && test -n "$start" && test "$start" = "$b" && skip=0
|
||||||
|
test $skip -eq 1 && { echo "skipping '$b'"; continue; }
|
||||||
|
|
||||||
|
t="$mysql_test_dir/t/$b.test"
|
||||||
|
r="$mysql_test_dir/r/$b.result"
|
||||||
|
c="$mysql_test_dir/r/$b.reject"
|
||||||
|
|
||||||
|
# Only test if $t exists; there is no $r for some tests
|
||||||
|
test -f $t || {
|
||||||
|
echo "test '$b' doesn't exist" >&2
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
args="-v -S /tmp/mysql.sock -R $r -x $t test"
|
||||||
|
echo "set args $args$run" > test-gdbinit
|
||||||
|
#if false && test -n "$run"
|
||||||
|
if test -n "$run" -o $gdb -eq 1
|
||||||
|
then
|
||||||
|
echo -e "$er>>> $b"
|
||||||
|
else
|
||||||
|
echo -e "$er>>> $b> \c"
|
||||||
|
read junk
|
||||||
|
fi
|
||||||
|
if test $gdb -eq 1
|
||||||
|
then
|
||||||
|
if [ -x "$top_builddir/libtool" ]; then
|
||||||
|
$top_builddir/libtool gdb -x test-gdbinit -q $mysqltest
|
||||||
|
else
|
||||||
|
gdb -x test-gdbinit -q $mysqltest
|
||||||
|
fi
|
||||||
|
res=$?
|
||||||
|
rm -f test-gdbinit
|
||||||
|
else
|
||||||
|
$mysqltest $args
|
||||||
|
res=$?
|
||||||
|
fi
|
||||||
|
|
||||||
|
test $res -eq 0 || echo "!!! error: $res"
|
||||||
|
done
|
@ -98,6 +98,11 @@ static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
|
|||||||
#define set_sigpipe(mysql)
|
#define set_sigpipe(mysql)
|
||||||
#define reset_sigpipe(mysql)
|
#define reset_sigpipe(mysql)
|
||||||
|
|
||||||
|
static MYSQL* spawn_init(MYSQL* parent, const char* host,
|
||||||
|
unsigned int port,
|
||||||
|
const char* user,
|
||||||
|
const char* passwd);
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
** read a packet from server. Give error message if socket was down
|
** read a packet from server. Give error message if socket was down
|
||||||
** or packet is an error message
|
** or packet is an error message
|
||||||
@ -762,6 +767,301 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* perform query on master */
|
||||||
|
int STDCALL mysql_master_query(MYSQL *mysql, const char *q,
|
||||||
|
unsigned int length)
|
||||||
|
{
|
||||||
|
if(mysql_master_send_query(mysql, q, length))
|
||||||
|
return 1;
|
||||||
|
return mysql_read_query_result(mysql);
|
||||||
|
}
|
||||||
|
|
||||||
|
int STDCALL mysql_master_send_query(MYSQL *mysql, const char *q,
|
||||||
|
unsigned int length)
|
||||||
|
{
|
||||||
|
MYSQL*master = mysql->master;
|
||||||
|
if (!length)
|
||||||
|
length = strlen(q);
|
||||||
|
if (!master->net.vio && !mysql_real_connect(master,0,0,0,0,0,0,0))
|
||||||
|
return 1;
|
||||||
|
mysql->last_used_con = master;
|
||||||
|
return simple_command(master, COM_QUERY, q, length, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* perform query on slave */
|
||||||
|
int STDCALL mysql_slave_query(MYSQL *mysql, const char *q,
|
||||||
|
unsigned int length)
|
||||||
|
{
|
||||||
|
if(mysql_slave_send_query(mysql, q, length))
|
||||||
|
return 1;
|
||||||
|
return mysql_read_query_result(mysql);
|
||||||
|
}
|
||||||
|
|
||||||
|
int STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q,
|
||||||
|
unsigned int length)
|
||||||
|
{
|
||||||
|
MYSQL* last_used_slave, *slave_to_use = 0;
|
||||||
|
|
||||||
|
if((last_used_slave = mysql->last_used_slave))
|
||||||
|
slave_to_use = last_used_slave->next_slave;
|
||||||
|
else
|
||||||
|
slave_to_use = mysql->next_slave;
|
||||||
|
/* next_slave is always safe to use - we have a circular list of slaves
|
||||||
|
if there are no slaves, mysql->next_slave == mysql
|
||||||
|
*/
|
||||||
|
mysql->last_used_con = mysql->last_used_slave = slave_to_use;
|
||||||
|
if(!length)
|
||||||
|
length = strlen(q);
|
||||||
|
if(!slave_to_use->net.vio && !mysql_real_connect(slave_to_use, 0,0,0,
|
||||||
|
0,0,0,0))
|
||||||
|
return 1;
|
||||||
|
return simple_command(slave_to_use, COM_QUERY, q, length, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* enable/disable parsing of all queries to decide
|
||||||
|
if they go on master or slave */
|
||||||
|
void STDCALL mysql_enable_rpl_parse(MYSQL* mysql)
|
||||||
|
{
|
||||||
|
mysql->options.rpl_parse = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void STDCALL mysql_disable_rpl_parse(MYSQL* mysql)
|
||||||
|
{
|
||||||
|
mysql->options.rpl_parse = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the value of the parse flag */
|
||||||
|
int STDCALL mysql_rpl_parse_enabled(MYSQL* mysql)
|
||||||
|
{
|
||||||
|
return mysql->options.rpl_parse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable/disable reads from master */
|
||||||
|
void STDCALL mysql_enable_reads_from_master(MYSQL* mysql)
|
||||||
|
{
|
||||||
|
mysql->options.no_master_reads = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void STDCALL mysql_disable_reads_from_master(MYSQL* mysql)
|
||||||
|
{
|
||||||
|
mysql->options.no_master_reads = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the value of the master read flag */
|
||||||
|
int STDCALL mysql_reads_from_master_enabled(MYSQL* mysql)
|
||||||
|
{
|
||||||
|
return !(mysql->options.no_master_reads);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We may get an error while doing replication internals.
|
||||||
|
In this case, we add a special explanation to the original
|
||||||
|
error
|
||||||
|
*/
|
||||||
|
static inline void expand_error(MYSQL* mysql, int error)
|
||||||
|
{
|
||||||
|
char tmp[MYSQL_ERRMSG_SIZE];
|
||||||
|
char* p, *tmp_end;
|
||||||
|
tmp_end = strnmov(tmp, mysql->net.last_error, MYSQL_ERRMSG_SIZE);
|
||||||
|
p = strnmov(mysql->net.last_error, ER(error), MYSQL_ERRMSG_SIZE);
|
||||||
|
memcpy(p, tmp, tmp_end - tmp);
|
||||||
|
mysql->net.last_errno = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function assumes we have just called SHOW SLAVE STATUS and have
|
||||||
|
read the given result and row
|
||||||
|
*/
|
||||||
|
static inline int get_master(MYSQL* mysql, MYSQL_RES* res, MYSQL_ROW row)
|
||||||
|
{
|
||||||
|
MYSQL* master;
|
||||||
|
if(mysql_num_fields(res) < 3)
|
||||||
|
return 1; /* safety */
|
||||||
|
|
||||||
|
/* use the same username and password as the original connection */
|
||||||
|
if(!(master = spawn_init(mysql, row[0], atoi(row[2]), 0, 0)))
|
||||||
|
return 1;
|
||||||
|
mysql->master = master;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assuming we already know that mysql points to a master connection,
|
||||||
|
retrieve all the slaves
|
||||||
|
*/
|
||||||
|
static inline int get_slaves_from_master(MYSQL* mysql)
|
||||||
|
{
|
||||||
|
MYSQL_RES* res = 0;
|
||||||
|
MYSQL_ROW row;
|
||||||
|
int error = 1;
|
||||||
|
int has_auth_info;
|
||||||
|
if (!mysql->net.vio && !mysql_real_connect(mysql,0,0,0,0,0,0,0))
|
||||||
|
{
|
||||||
|
expand_error(mysql, CR_PROBE_MASTER_CONNECT);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mysql_query(mysql, "SHOW SLAVE HOSTS") ||
|
||||||
|
!(res = mysql_store_result(mysql)))
|
||||||
|
{
|
||||||
|
expand_error(mysql, CR_PROBE_SLAVE_HOSTS);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mysql_num_fields(res))
|
||||||
|
{
|
||||||
|
case 3: has_auth_info = 0; break;
|
||||||
|
case 5: has_auth_info = 1; break;
|
||||||
|
default:
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((row = mysql_fetch_row(res)))
|
||||||
|
{
|
||||||
|
MYSQL* slave;
|
||||||
|
const char* tmp_user, *tmp_pass;
|
||||||
|
|
||||||
|
if (has_auth_info)
|
||||||
|
{
|
||||||
|
tmp_user = row[3];
|
||||||
|
tmp_pass = row[4];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tmp_user = mysql->user;
|
||||||
|
tmp_pass = mysql->passwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(slave = spawn_init(mysql, row[1], atoi(row[2]),
|
||||||
|
tmp_user, tmp_pass)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* Now add slave into the circular linked list */
|
||||||
|
slave->next_slave = mysql->next_slave;
|
||||||
|
mysql->next_slave = slave;
|
||||||
|
}
|
||||||
|
error = 0;
|
||||||
|
err:
|
||||||
|
if(res)
|
||||||
|
mysql_free_result(res);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int STDCALL mysql_rpl_probe(MYSQL* mysql)
|
||||||
|
{
|
||||||
|
MYSQL_RES* res = 0;
|
||||||
|
MYSQL_ROW row;
|
||||||
|
int error = 1;
|
||||||
|
/* first determine the replication role of the server we connected to
|
||||||
|
the most reliable way to do this is to run SHOW SLAVE STATUS and see
|
||||||
|
if we have a non-empty master host. This is still not fool-proof -
|
||||||
|
it is not a sin to have a master that has a dormant slave thread with
|
||||||
|
a non-empty master host. However, it is more reliable to check
|
||||||
|
for empty master than whether the slave thread is actually running
|
||||||
|
*/
|
||||||
|
if (mysql_query(mysql, "SHOW SLAVE STATUS") ||
|
||||||
|
!(res = mysql_store_result(mysql)))
|
||||||
|
{
|
||||||
|
expand_error(mysql, CR_PROBE_SLAVE_STATUS);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(row = mysql_fetch_row(res)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* check master host for emptiness/NULL */
|
||||||
|
if (row[0] && *(row[0]))
|
||||||
|
{
|
||||||
|
/* this is a slave, ask it for the master */
|
||||||
|
if (get_master(mysql, res, row) || get_slaves_from_master(mysql))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mysql->master = mysql;
|
||||||
|
if (get_slaves_from_master(mysql))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
err:
|
||||||
|
if(res)
|
||||||
|
mysql_free_result(res);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* make a not so fool-proof decision on where the query should go, to
|
||||||
|
the master or the slave. Ideally the user should always make this
|
||||||
|
decision himself with mysql_master_query() or mysql_slave_query().
|
||||||
|
However, to be able to more easily port the old code, we support the
|
||||||
|
option of an educated guess - this should work for most applications,
|
||||||
|
however, it may make the wrong decision in some particular cases. If
|
||||||
|
that happens, the user would have to change the code to call
|
||||||
|
mysql_master_query() or mysql_slave_query() explicitly in the place
|
||||||
|
where we have made the wrong decision
|
||||||
|
*/
|
||||||
|
enum mysql_rpl_type
|
||||||
|
STDCALL mysql_rpl_query_type(const char* q, int len)
|
||||||
|
{
|
||||||
|
const char* q_end;
|
||||||
|
q_end = (len) ? q + len : strend(q);
|
||||||
|
for(; q < q_end; ++q)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
if(isalpha(c=*q))
|
||||||
|
switch(tolower(c))
|
||||||
|
{
|
||||||
|
case 'i': /* insert */
|
||||||
|
case 'u': /* update or unlock tables */
|
||||||
|
case 'l': /* lock tables or load data infile */
|
||||||
|
case 'd': /* drop or delete */
|
||||||
|
case 'a': /* alter */
|
||||||
|
return MYSQL_RPL_MASTER;
|
||||||
|
case 'c': /* create or check */
|
||||||
|
return tolower(q[1]) == 'h' ? MYSQL_RPL_ADMIN : MYSQL_RPL_MASTER ;
|
||||||
|
case 's': /* select or show */
|
||||||
|
return tolower(q[1] == 'h') ? MYSQL_RPL_ADMIN : MYSQL_RPL_SLAVE;
|
||||||
|
case 'f': /* flush */
|
||||||
|
case 'r': /* repair */
|
||||||
|
case 'g': /* grant */
|
||||||
|
return MYSQL_RPL_ADMIN;
|
||||||
|
default:
|
||||||
|
return MYSQL_RPL_SLAVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MYSQL* spawn_init(MYSQL* parent, const char* host,
|
||||||
|
unsigned int port,
|
||||||
|
const char* user,
|
||||||
|
const char* passwd)
|
||||||
|
{
|
||||||
|
MYSQL* child;
|
||||||
|
if (!(child = mysql_init(0)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
child->options.user = my_strdup((user) ? user :
|
||||||
|
(parent->user ? parent->user :
|
||||||
|
parent->options.user), MYF(0));
|
||||||
|
child->options.password = my_strdup((passwd) ? passwd : (parent->passwd ?
|
||||||
|
parent->passwd :
|
||||||
|
parent->options.password), MYF(0));
|
||||||
|
child->options.port = port;
|
||||||
|
child->options.host = my_strdup((host) ? host : (parent->host ?
|
||||||
|
parent->host :
|
||||||
|
parent->options.host), MYF(0));
|
||||||
|
if(parent->db)
|
||||||
|
child->options.db = my_strdup(parent->db, MYF(0));
|
||||||
|
else if(parent->options.db)
|
||||||
|
child->options.db = my_strdup(parent->options.db, MYF(0));
|
||||||
|
|
||||||
|
child->options.rpl_parse = child->options.rpl_probe = child->rpl_pivot = 0;
|
||||||
|
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
** Init MySQL structure or allocate one
|
** Init MySQL structure or allocate one
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -128,7 +128,7 @@ DO_GDB=""
|
|||||||
DO_DDD=""
|
DO_DDD=""
|
||||||
DO_CLIENT_GDB=""
|
DO_CLIENT_GDB=""
|
||||||
SLEEP_TIME=2
|
SLEEP_TIME=2
|
||||||
CHARACTER_SET=latin1_de
|
CHARACTER_SET=latin1
|
||||||
DBUSER=""
|
DBUSER=""
|
||||||
|
|
||||||
while test $# -gt 0; do
|
while test $# -gt 0; do
|
||||||
|
@ -684,7 +684,9 @@ static sig_handler print_signal_warning(int sig)
|
|||||||
void unireg_end(int signal_number __attribute__((unused)))
|
void unireg_end(int signal_number __attribute__((unused)))
|
||||||
{
|
{
|
||||||
clean_up();
|
clean_up();
|
||||||
#ifndef OS2
|
#if defined(EMBEDDED_LIBRARY)
|
||||||
|
exit(0); // XXX QQ: this is a temporary hack (I hope)
|
||||||
|
#elif !defined(OS2)
|
||||||
pthread_exit(0); // Exit is in main thread
|
pthread_exit(0); // Exit is in main thread
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user