diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/.cvsignore | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | tests/CMakeLists.txt | 27 | ||||
-rw-r--r-- | tests/Makefile.am | 65 | ||||
-rw-r--r-- | tests/async_queries.c | 435 | ||||
-rwxr-xr-x | tests/big_record.pl | 17 | ||||
-rw-r--r-- | tests/bug25714.c | 6 | ||||
-rw-r--r-- | tests/check_async_queries.pl | 73 | ||||
-rwxr-xr-x | tests/drop_test.pl | 16 | ||||
-rwxr-xr-x | tests/export.pl | 15 | ||||
-rwxr-xr-x | tests/fork2_test.pl | 15 | ||||
-rwxr-xr-x | tests/fork_big.pl | 16 | ||||
-rw-r--r-- | tests/fork_big2.pl | 16 | ||||
-rwxr-xr-x | tests/grant.pl | 1 | ||||
-rwxr-xr-x | tests/index_corrupt.pl | 16 | ||||
-rwxr-xr-x | tests/insert_and_repair.pl | 16 | ||||
-rwxr-xr-x | tests/lock_test.pl | 15 | ||||
-rw-r--r-- | tests/myisam-big-rows.tst | 2 | ||||
-rw-r--r-- | tests/mysql_client_fw.c | 1516 | ||||
-rw-r--r-- | tests/mysql_client_test.c | 1876 | ||||
-rw-r--r-- | tests/nonblock-wrappers.h | 516 | ||||
-rwxr-xr-x | tests/pmail.pl | 16 | ||||
-rwxr-xr-x | tests/rename_test.pl | 16 | ||||
-rwxr-xr-x | tests/table_types.pl | 16 | ||||
-rwxr-xr-x | tests/test_delayed_insert.pl | 15 | ||||
-rw-r--r-- | tests/thread_test.c | 51 | ||||
-rwxr-xr-x | tests/truncate.pl | 16 |
26 files changed, 3661 insertions, 1130 deletions
diff --git a/tests/.cvsignore b/tests/.cvsignore deleted file mode 100644 index 282522db034..00000000000 --- a/tests/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile -Makefile.in diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 967ebae2e22..0acad6bf30b 100755..100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2006 MySQL AB +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # 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 @@ -11,18 +11,27 @@ # # 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -# About "mysqlclient_notls", see note in "client/CMakeLists.txt" +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADD_DEFINITIONS("-DMYSQL_CLIENT") INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) -ADD_EXECUTABLE(mysql_client_test mysql_client_test.c ../mysys/my_memmem.c) -TARGET_LINK_LIBRARIES(mysql_client_test mysqlclient wsock32) +ADD_EXECUTABLE(mysql_client_test mysql_client_test.c) +TARGET_LINK_LIBRARIES(mysql_client_test mysqlclient) +SET_TARGET_PROPERTIES(mysql_client_test PROPERTIES LINKER_LANGUAGE CXX) + +IF(WITH_UNIT_TESTS) + ADD_EXECUTABLE(bug25714 bug25714.c) + TARGET_LINK_LIBRARIES(bug25714 mysqlclient) + SET_TARGET_PROPERTIES(bug25714 PROPERTIES LINKER_LANGUAGE CXX) +ENDIF() -ADD_EXECUTABLE(bug25714 bug25714.c) -TARGET_LINK_LIBRARIES(bug25714 mysqlclient wsock32) +INSTALL(TARGETS mysql_client_test DESTINATION ${INSTALL_BINDIR} COMPONENT Test) -INSTALL(TARGETS mysql_client_test DESTINATION bin COMPONENT Test) +CHECK_INCLUDE_FILE(event.h HAVE_EVENT_H) +FIND_LIBRARY(EVENT_LIBRARY event) +IF(HAVE_EVENT_H AND EVENT_LIBRARY) + ADD_EXECUTABLE(async_queries async_queries.c) + TARGET_LINK_LIBRARIES(async_queries mysqlclient ${EVENT_LIBRARY}) +ENDIF() diff --git a/tests/Makefile.am b/tests/Makefile.am deleted file mode 100644 index 48ac873fcd0..00000000000 --- a/tests/Makefile.am +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2000-2007 MySQL AB, 2009 Sun Microsystems, Inc. -# Use is subject to license terms. -# -# This program 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; version 2 -# of the License. -# -# 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 -# 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., 51 Franklin St, Fifth Floor, Boston, -# MA 02110-1301, USA - -## Process this file with automake to create Makefile.in - - -if THREAD_SAFE_CLIENT -LIBMYSQLCLIENT_LA = $(top_builddir)/libmysql_r/libmysqlclient_r.la -else -LIBMYSQLCLIENT_LA = $(top_builddir)/libmysql/libmysqlclient.la -endif - -EXTRA_DIST = auto_increment.res auto_increment.tst \ - function.res function.tst lock_test.pl lock_test.res \ - export.pl big_record.pl \ - fork2_test.pl fork_big.pl \ - insert_and_repair.pl \ - grant.pl grant.res test_delayed_insert.pl \ - pmail.pl mail_to_db.pl table_types.pl \ - myisam-big-rows.tst \ - mysql_client_fw.c \ - CMakeLists.txt - -bin_PROGRAMS = mysql_client_test -noinst_PROGRAMS = insert_test select_test thread_test bug25714 - -INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ - $(openssl_includes) -LIBS = @CLIENT_LIBS@ -LDADD = @CLIENT_EXTRA_LDFLAGS@ \ - $(LIBMYSQLCLIENT_LA) - -mysql_client_test_LDADD= $(LDADD) $(CXXLDFLAGS) -mysql_client_test_SOURCES= mysql_client_test.c\ - $(top_srcdir)/mysys/my_memmem.c -mysql_client_test.o: mysql_client_fw.c - -insert_test_SOURCES= insert_test.c -select_test_SOURCES= select_test.c -insert_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) -select_test_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) - -bug25714_SOURCES= bug25714.c -bug25714_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) - -# Fix for mit-threads -DEFS = -DMYSQL_CLIENT_NO_THREADS - -thread_test.o: thread_test.c - $(COMPILE) -c $(INCLUDES) $< diff --git a/tests/async_queries.c b/tests/async_queries.c new file mode 100644 index 00000000000..b9393ca76ab --- /dev/null +++ b/tests/async_queries.c @@ -0,0 +1,435 @@ +/* + Copyright 2011 Kristian Nielsen and Monty Program Ab. + + This file is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this. If not, see <http://www.gnu.org/licenses/>. +*/ + + +/* + Run a set of queries in parallel against a server using the non-blocking + API, and compare to running same queries with the normal blocking API. +*/ + +#include <sys/time.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <my_global.h> +#include <my_sys.h> +#include <mysql.h> +#include <my_getopt.h> + +#include <event.h> + + +#define SL(s) (s), sizeof(s) +static const char *my_groups[]= { "client", NULL }; + +/* Maintaining a list of queries to run. */ +struct query_entry { + struct query_entry *next; + char *query; + int index; +}; +static struct query_entry *query_list; +static struct query_entry **tail_ptr= &query_list; +static int query_counter= 0; + + +/* State kept for each connection. */ +struct state_data { + int ST; /* State machine current state */ + struct event ev_mysql; + MYSQL mysql; + MYSQL_RES *result; + MYSQL *ret; + int err; + MYSQL_ROW row; + struct query_entry *query_element; + int index; +}; + + +static const char *opt_db= NULL; +static const char *opt_user= NULL; +static const char *opt_password= NULL; +static int tty_password= 0; +static const char *opt_host= NULL; +static const char *opt_socket= NULL; +static unsigned int opt_port= 0; +static unsigned int opt_connections= 5; +static const char *opt_query_file= NULL; + +static struct my_option options[] = +{ + {"database", 'D', "Database to use", &opt_db, &opt_db, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, + 0, 0, 0, 0, 0}, + {"host", 'h', "Connect to host", &opt_host, &opt_host, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"password", 'p', + "Password to use when connecting to server. If password is not given it's asked from the tty.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"port", 'P', "Port number to use for connection.", + &opt_port, &opt_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"socket", 'S', "Socket file to use for connection", + &opt_socket, &opt_socket, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"user", 'u', "User for login if not current user", &opt_user, + &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"connections", 'n', "Number of simultaneous connections/queries.", + &opt_connections, &opt_connections, 0, GET_UINT, REQUIRED_ARG, + 5, 0, 0, 0, 0, 0}, + {"queryfile", 'q', "Name of file containing extra queries to run", + &opt_query_file, &opt_query_file, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + +static void +fatal(struct state_data *sd, const char *msg) +{ + fprintf(stderr, "%s: %s\n", msg, (sd ? mysql_error(&sd->mysql) : "")); + exit(1); +} + + +static void state_machine_handler(int fd, short event, void *arg); + +static void +next_event(int new_st, int status, struct state_data *sd) +{ + short wait_event= 0; + struct timeval tv, *ptv; + int fd; + + if (status & MYSQL_WAIT_READ) + wait_event|= EV_READ; + if (status & MYSQL_WAIT_WRITE) + wait_event|= EV_WRITE; + if (wait_event) + fd= mysql_get_socket(&sd->mysql); + else + fd= -1; + if (status & MYSQL_WAIT_TIMEOUT) + { + tv.tv_sec= mysql_get_timeout_value(&sd->mysql); + tv.tv_usec= 0; + ptv= &tv; + } + else + ptv= NULL; + event_set(&sd->ev_mysql, fd, wait_event, state_machine_handler, sd); + event_add(&sd->ev_mysql, ptv); + sd->ST= new_st; +} + +static int +mysql_status(short event) +{ + int status= 0; + if (event & EV_READ) + status|= MYSQL_WAIT_READ; + if (event & EV_WRITE) + status|= MYSQL_WAIT_WRITE; + if (event & EV_TIMEOUT) + status|= MYSQL_WAIT_TIMEOUT; + return status; +} + + +static int num_active_connections; + +/* Shortcut for going to new state immediately without waiting. */ +#define NEXT_IMMEDIATE(sd_, new_st) do { sd_->ST= new_st; goto again; } while (0) + +static void +state_machine_handler(int fd __attribute__((unused)), short event, void *arg) +{ + struct state_data *sd= arg; + int status; + +again: + switch(sd->ST) + { + case 0: + /* Initial state, start making the connection. */ + status= mysql_real_connect_start(&sd->ret, &sd->mysql, opt_host, opt_user, opt_password, opt_db, opt_port, opt_socket, 0); + if (status) + /* Wait for connect to complete. */ + next_event(1, status, sd); + else + NEXT_IMMEDIATE(sd, 9); + break; + + case 1: + status= mysql_real_connect_cont(&sd->ret, &sd->mysql, mysql_status(event)); + if (status) + next_event(1, status, sd); + else + NEXT_IMMEDIATE(sd, 9); + break; + + case 9: + if (!sd->ret) + fatal(sd, "Failed to mysql_real_connect()"); + NEXT_IMMEDIATE(sd, 10); + break; + + case 10: + /* Now run the next query. */ + sd->query_element= query_list; + if (!sd->query_element) + { + /* No more queries, end the connection. */ + NEXT_IMMEDIATE(sd, 40); + } + query_list= query_list->next; + + sd->index= sd->query_element->index; + printf("%d ! %s\n", sd->index, sd->query_element->query); + status= mysql_real_query_start(&sd->err, &sd->mysql, sd->query_element->query, + strlen(sd->query_element->query)); + if (status) + next_event(11, status, sd); + else + NEXT_IMMEDIATE(sd, 20); + break; + + case 11: + status= mysql_real_query_cont(&sd->err, &sd->mysql, mysql_status(event)); + if (status) + next_event(11, status, sd); + else + NEXT_IMMEDIATE(sd, 20); + break; + + case 20: + my_free(sd->query_element->query); + my_free(sd->query_element); + if (sd->err) + { + printf("%d | Error: %s\n", sd->index, mysql_error(&sd->mysql)); + NEXT_IMMEDIATE(sd, 10); + } + else + { + sd->result= mysql_use_result(&sd->mysql); + if (!sd->result) + fatal(sd, "mysql_use_result() returns error"); + NEXT_IMMEDIATE(sd, 30); + } + break; + + case 30: + status= mysql_fetch_row_start(&sd->row, sd->result); + if (status) + next_event(31, status, sd); + else + NEXT_IMMEDIATE(sd, 39); + break; + + case 31: + status= mysql_fetch_row_cont(&sd->row, sd->result, mysql_status(event)); + if (status) + next_event(31, status, sd); + else + NEXT_IMMEDIATE(sd, 39); + break; + + case 39: + if (sd->row) + { + /* Got a row. */ + unsigned int i; + printf("%d - ", sd->index); + for (i= 0; i < mysql_num_fields(sd->result); i++) + printf("%s%s", (i ? "\t" : ""), (sd->row[i] ? sd->row[i] : "(null)")); + printf ("\n"); + NEXT_IMMEDIATE(sd, 30); + } + else + { + if (mysql_errno(&sd->mysql)) + { + /* An error occured. */ + printf("%d | Error: %s\n", sd->index, mysql_error(&sd->mysql)); + } + else + { + /* EOF. */ + printf("%d | EOF\n", sd->index); + } + mysql_free_result(sd->result); + NEXT_IMMEDIATE(sd, 10); + } + break; + + case 40: + status= mysql_close_start(&sd->mysql); + if (status) + next_event(41, status, sd); + else + NEXT_IMMEDIATE(sd, 50); + break; + + case 41: + status= mysql_close_cont(&sd->mysql, mysql_status(event)); + if (status) + next_event(41, status, sd); + else + NEXT_IMMEDIATE(sd, 50); + break; + + case 50: + /* We are done! */ + num_active_connections--; + if (num_active_connections == 0) + event_loopbreak(); + break; + + default: + abort(); + } +} + + +void +add_query(const char *q) +{ + struct query_entry *e; + char *q2; + size_t len; + + e= my_malloc(sizeof(*e), MYF(0)); + q2= my_strdup(q, MYF(0)); + if (!e || !q2) + fatal(NULL, "Out of memory"); + + /* Remove any trailing newline. */ + len= strlen(q2); + if (q2[len] == '\n') + q2[len--]= '\0'; + if (q2[len] == '\r') + q2[len--]= '\0'; + + e->next= NULL; + e->query= q2; + e->index= query_counter++; + *tail_ptr= e; + tail_ptr= &e->next; +} + + +static my_bool +handle_option(int optid, const struct my_option *opt __attribute__((unused)), + char *arg) +{ + switch (optid) + { + case '?': + printf("Usage: async_queries [OPTIONS] query ...\n"); + my_print_help(options); + my_print_variables(options); + exit(0); + break; + + case 'p': + if (arg) + opt_password= arg; + else + tty_password= 1; + break; + } + + return 0; +} + + +int +main(int argc, char *argv[]) +{ + struct state_data *sds; + unsigned int i; + int err; + struct event_base *libevent_base; + + err= handle_options(&argc, &argv, options, handle_option); + if (err) + exit(err); + if (tty_password) + opt_password= get_tty_password(NullS); + + if (opt_query_file) + { + FILE *f= fopen(opt_query_file, "r"); + char buf[65536]; + if (!f) + fatal(NULL, "Cannot open query file"); + while (!feof(f)) + { + if (!fgets(buf, sizeof(buf), f)) + break; + add_query(buf); + } + fclose(f); + } + /* Add extra queries directly on command line. */ + while (argc > 0) + { + --argc; + add_query(*argv++); + } + + sds= my_malloc(opt_connections * sizeof(*sds), MYF(0)); + if (!sds) + fatal(NULL, "Out of memory"); + + libevent_base= event_init(); + + err= mysql_library_init(argc, argv, (char **)my_groups); + if (err) + { + fprintf(stderr, "Fatal: mysql_library_init() returns error: %d\n", err); + exit(1); + } + + num_active_connections= 0; + for (i= 0; i < opt_connections; i++) + { + mysql_init(&sds[i].mysql); + mysql_options(&sds[i].mysql, MYSQL_OPT_NONBLOCK, 0); + mysql_options(&sds[i].mysql, MYSQL_READ_DEFAULT_GROUP, "async_queries"); + + /* + We put the initial connect call in the first state 0 of the state machine + and run that manually, just to have everything in one place. + */ + sds[i].ST= 0; + num_active_connections++; + state_machine_handler(-1, -1, &sds[i]); + } + + event_dispatch(); + + free(sds); + + mysql_library_end(); + + event_base_free(libevent_base); + + return 0; +} diff --git a/tests/big_record.pl b/tests/big_record.pl index fbe94e3540f..0d5766e5f5d 100755 --- a/tests/big_record.pl +++ b/tests/big_record.pl @@ -1,8 +1,23 @@ #!/usr/bin/perl +# Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +# +# 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; version 2 of the License. +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + # This is a test with stores big records in a blob. # Note that for the default test the mysql server should have been -# started with at least 'mysqld -O max_allowed_packet=30M' and you should have +# started with at least 'mysqld --max_allowed_packet=30M' and you should have # at least 256M memory in your computer. use DBI; diff --git a/tests/bug25714.c b/tests/bug25714.c index ad3b863dd75..40c631d76a5 100644 --- a/tests/bug25714.c +++ b/tests/bug25714.c @@ -1,5 +1,4 @@ -/* - Copyright (c) 2007 MySQL AB, 2009 Sun Microsystems, Inc. +/* Copyright (c) 2007 MySQL AB, 2009 Sun Microsystems, Inc. Use is subject to license terms. This program is free software; you can redistribute it and/or modify @@ -13,8 +12,7 @@ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <my_global.h> #include <my_sys.h> diff --git a/tests/check_async_queries.pl b/tests/check_async_queries.pl new file mode 100644 index 00000000000..b599bc334d3 --- /dev/null +++ b/tests/check_async_queries.pl @@ -0,0 +1,73 @@ +#! /usr/bin/perl + +# Read the output of async_queries.c. Run the queries again serially, using +# the normal (not asynchronous) API. Compare the two results for correctness. + +use strict; +use warnings; + +use DBI; + +my $D= []; + +die "Usage: $0 <host> <user> <password> <database>\n" + unless @ARGV == 4; + +my $dbh= DBI->connect("DBI:mysql:database=$ARGV[3];host=$ARGV[0]", + $ARGV[1], $ARGV[2], + { RaiseError => 1, PrintError => 0 }); + +while (<STDIN>) { + chomp; + if (/^([0-9]+) ! (.*);$/) { + my ($index, $query)= ($1, $2); + $D->[$index]= { QUERY => $query, OUTPUT => [] }; + } elsif (/^([0-9]+) - (.*)$/) { + my ($index, $data)= ($1, $2); + push @{$D->[$index]{OUTPUT}}, $data; + } elsif (/^([0-9]+) \| Error: (.*)$/) { + my ($index, $errmsg)= ($1, $2); + my $rows; + my $res= eval { + my $stm= $dbh->prepare($D->[$index]{QUERY}); + $stm->execute(); + $rows= $stm->fetchall_arrayref(); + 1; + }; + if ($res) { + die "Query $index succeeded, but should have failed with error.\nquery=$D->[$index]{QUERY}\nerror=$errmsg\n"; + } + my $errmsg2= $@; + if ($errmsg2 =~ /^DBD::.*failed: (.*) at .*$/s) { + $errmsg2= $1; + } else { + die "Unexpected DBD error message format: '$errmsg2'\n"; + } + if ($errmsg2 ne $errmsg) { + die "Query $index failed with different error message\nquery=$D->[$index]{QUERY}\nerror1=$errmsg\nerror2=$errmsg2\n"; + } + print "OK $index\n"; + delete $D->[$index]; + } elsif (/^([0-9]+) \| EOF$/) { + my $index= $1; + my $rows; + my $res= eval { + my $stm= $dbh->prepare($D->[$index]{QUERY}); + $stm->execute(); + $rows= $stm->fetchall_arrayref(); + 1; + }; + if (!$res) { + die "Query $index failed, but should have succeeded.\nquery=$D->[$index]{QUERY}\nerror=$@\n"; + } + my $result_string= join("\n", sort @{$D->[$index]{OUTPUT}}); + my $result_string2= join("\n", sort(map(join("\t", map((defined($_) ? $_ : "(null)"), @$_)), @$rows))); + if ($result_string ne $result_string2) { + die "Query $index result difference.\nquery=$D->[$index]{QUERY}\noutput1=\n$$result_string\noutput2=\n$result_string2\n"; + } + delete $D->[$index]; + } else { + die "Unexpected line: '$_'\n"; + } +} +$dbh->disconnect(); diff --git a/tests/drop_test.pl b/tests/drop_test.pl index 9dcadf45c2e..272c4029e0f 100755 --- a/tests/drop_test.pl +++ b/tests/drop_test.pl @@ -1,4 +1,20 @@ #!/usr/bin/perl -w + +# Copyright (C) 2000 MySQL 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; version 2 of the License. +# +# 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 is a test with uses processes to insert, select and drop tables. # diff --git a/tests/export.pl b/tests/export.pl index 29f0d1af8ff..d543ede8697 100755 --- a/tests/export.pl +++ b/tests/export.pl @@ -1,5 +1,20 @@ #!/usr/bin/perl +# Copyright (C) 2000, 2001 MySQL 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; version 2 of the License. +# +# 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 is a test with uses two processes to a database. # The other inserts records in two tables, the other does a lot of joins # on these. diff --git a/tests/fork2_test.pl b/tests/fork2_test.pl index 19fab5a67d6..64e3e060b09 100755 --- a/tests/fork2_test.pl +++ b/tests/fork2_test.pl @@ -1,5 +1,20 @@ #!/usr/bin/perl -w +# Copyright (C) 2000, 2001 MySQL 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; version 2 of the License. +# +# 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 is a test with uses 5 processes to insert, update and select from # two tables. # One inserts records in the tables, one updates some record in it and diff --git a/tests/fork_big.pl b/tests/fork_big.pl index 5c4f11b00e2..a674f7f7164 100755 --- a/tests/fork_big.pl +++ b/tests/fork_big.pl @@ -1,4 +1,20 @@ #!/usr/bin/perl -w + +# Copyright (C) 2001 MySQL 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; version 2 of the License. +# +# 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 is a test with uses many processes to test a MySQL server. # diff --git a/tests/fork_big2.pl b/tests/fork_big2.pl index f22aeaa6713..77b6f305ef5 100644 --- a/tests/fork_big2.pl +++ b/tests/fork_big2.pl @@ -1,4 +1,20 @@ #!/usr/bin/perl -w + +# Copyright (C) 2002, 2005 MySQL 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; version 2 of the License. +# +# 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 is a test with uses many processes to test a MySQL server. # diff --git a/tests/grant.pl b/tests/grant.pl index a2465d19bb1..23a7d2110fb 100755 --- a/tests/grant.pl +++ b/tests/grant.pl @@ -1,4 +1,5 @@ #!/usr/bin/perl + # Copyright (c) 2000, 2005 MySQL AB, 2009 Sun Microsystems, Inc. # Use is subject to license terms. # diff --git a/tests/index_corrupt.pl b/tests/index_corrupt.pl index 19bf54f5d11..fa4c8151277 100755 --- a/tests/index_corrupt.pl +++ b/tests/index_corrupt.pl @@ -1,4 +1,20 @@ #!/usr/bin/perl -w + +# Copyright (C) 2005 MySQL 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; version 2 of the License. +# +# 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 is a test for a key cache bug (bug #10167) # To expose the bug mysqld should be started with --key-buffer-size=64K diff --git a/tests/insert_and_repair.pl b/tests/insert_and_repair.pl index 1c7186bb651..00ab20f051b 100755 --- a/tests/insert_and_repair.pl +++ b/tests/insert_and_repair.pl @@ -1,4 +1,20 @@ #!/usr/bin/perl -w + +# Copyright (C) 2000, 2001 MySQL 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; version 2 of the License. +# +# 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 is a test of insert and repair/check. # diff --git a/tests/lock_test.pl b/tests/lock_test.pl index 5daeeddad8e..a40bec681f6 100755 --- a/tests/lock_test.pl +++ b/tests/lock_test.pl @@ -1,5 +1,20 @@ #!/usr/bin/perl +# Copyright (C) 2000 MySQL 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; version 2 of the License. +# +# 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 is a test with uses two processes to a database. # The other inserts records in two tables, the other does a lot of joins # on these. diff --git a/tests/myisam-big-rows.tst b/tests/myisam-big-rows.tst index 56c06f4820f..97147999f87 100644 --- a/tests/myisam-big-rows.tst +++ b/tests/myisam-big-rows.tst @@ -1,7 +1,7 @@ # # Test rows with length above > 16M # Note that for this to work, you should start mysqld with -# -O max_allowed_packet=32M +# --max_allowed_packet=32M # drop table if exists t1; diff --git a/tests/mysql_client_fw.c b/tests/mysql_client_fw.c index 222e5a75055..9ce4737d874 100644 --- a/tests/mysql_client_fw.c +++ b/tests/mysql_client_fw.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. 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 @@ -17,11 +17,25 @@ #include <my_sys.h> #include <mysql.h> #include <errmsg.h> +#include <my_compare.h> #include <my_getopt.h> #include <m_string.h> #include <mysqld_error.h> -#include <my_handler.h> #include <sql_common.h> +#include <mysql/client_plugin.h> + +/* + If non_blocking_api_enabled is true, we will re-define all the blocking + API functions as wrappers that call the corresponding non-blocking API + and use poll()/select() to wait for them to complete. This way we can get + a good coverage testing of the non-blocking API as well. +*/ +#include <my_context.h> +static my_bool non_blocking_api_enabled= 0; +#if !defined(EMBEDDED_LIBRARY) && !defined(MY_CONTEXT_DISABLE) +#define WRAP_NONBLOCK_ENABLED non_blocking_api_enabled +#include "nonblock-wrappers.h" +#endif #define VER "2.1" #define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ @@ -47,6 +61,8 @@ static unsigned int test_count= 0; static unsigned int opt_count= 0; static unsigned int iter_count= 0; static my_bool have_innodb= FALSE; +static char *opt_plugin_dir= 0, *opt_default_auth= 0; +static unsigned int opt_drop_db= 1; static const char *opt_basedir= "./"; static const char *opt_vardir= "mysql-test/var"; @@ -57,10 +73,10 @@ static int embedded_server_arg_count= 0; static char *embedded_server_args[MAX_SERVER_ARGS]; static const char *embedded_server_groups[]= { -"server", -"embedded", -"mysql_client_test_SERVER", -NullS + "server", + "embedded", + "mysql_client_test_SERVER", + NullS }; static time_t start_time, end_time; @@ -70,8 +86,8 @@ const char *default_dbug_option= "d:t:o,/tmp/mysql_client_test.trace"; struct my_tests_st { -const char *name; -void (*function)(); + const char *name; + void (*function)(); }; #define myheader(str) \ @@ -95,33 +111,34 @@ DBUG_PRINT("test", ("name: %s", str)); \ static void print_error(const char *msg); static void print_st_error(MYSQL_STMT *stmt, const char *msg); -static void client_disconnect(MYSQL* mysql, my_bool drop_db); +static void client_disconnect(MYSQL* mysql); /* -Abort unless given experssion is non-zero. + Abort unless given experssion is non-zero. -SYNOPSIS -DIE_UNLESS(expr) + SYNOPSIS + DIE_UNLESS(expr) -DESCRIPTION -We can't use any kind of system assert as we need to -preserve tested invariants in release builds as well. + DESCRIPTION + We can't use any kind of system assert as we need to + preserve tested invariants in release builds as well. */ -#define DIE_UNLESS(expr) \ -((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0))) -#define DIE_IF(expr) \ -((void) ((expr) ? (die(__FILE__, __LINE__, #expr), 0) : 0)) -#define DIE(expr) \ -die(__FILE__, __LINE__, #expr) +#define DIE_UNLESS(expr) \ + ((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0))) +#define DIE_IF(expr) \ + ((void) ((expr) ? (die(__FILE__, __LINE__, #expr), 0) : 0)) +#define DIE(expr) \ + die(__FILE__, __LINE__, #expr) static void die(const char *file, int line, const char *expr) { - fflush(stdout); - fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr); - fflush(stderr); - exit(1); + fflush(stdout); + fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr); + fprintf(stderr, "MySQL error %d: %s\n", mysql_errno(0), mysql_error(0)); + fflush(stderr); + exit(1); } @@ -179,7 +196,7 @@ static void die(const char *file, int line, const char *expr) static int cmp_double(double *a, double *b) { - return *a == *b; + return *a == *b; } @@ -187,57 +204,64 @@ static int cmp_double(double *a, double *b) static void print_error(const char *msg) { - if (!opt_silent) - { - if (mysql && mysql_errno(mysql)) - { - if (mysql->server_version) - fprintf(stdout, "\n [MySQL-%s]", mysql->server_version); - else - fprintf(stdout, "\n [MySQL]"); - fprintf(stdout, "[%d] %s\n", mysql_errno(mysql), mysql_error(mysql)); - } - else if (msg) - fprintf(stderr, " [MySQL] %s\n", msg); - } + if (!opt_silent) + { + if (mysql && mysql_errno(mysql)) + { + if (mysql->server_version) + fprintf(stdout, "\n [MySQL-%s]", mysql->server_version); + else + fprintf(stdout, "\n [MySQL]"); + fprintf(stdout, "[%d] %s\n", mysql_errno(mysql), mysql_error(mysql)); + } + else if (msg) + fprintf(stderr, " [MySQL] %s\n", msg); + } } static void print_st_error(MYSQL_STMT *stmt, const char *msg) { - if (!opt_silent) - { - if (stmt && mysql_stmt_errno(stmt)) - { - if (stmt->mysql && stmt->mysql->server_version) - fprintf(stdout, "\n [MySQL-%s]", stmt->mysql->server_version); - else - fprintf(stdout, "\n [MySQL]"); - - fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt), - mysql_stmt_error(stmt)); - } - else if (msg) - fprintf(stderr, " [MySQL] %s\n", msg); - } + if (!opt_silent) + { + if (stmt && mysql_stmt_errno(stmt)) + { + if (stmt->mysql && stmt->mysql->server_version) + fprintf(stdout, "\n [MySQL-%s]", stmt->mysql->server_version); + else + fprintf(stdout, "\n [MySQL]"); + + fprintf(stdout, "[%d] %s\n", mysql_stmt_errno(stmt), + mysql_stmt_error(stmt)); + } + else if (msg) + fprintf(stderr, " [MySQL] %s\n", msg); + } } /* -Enhanced version of mysql_client_init(), which may also set shared memory -base on Windows. + Enhanced version of mysql_client_init(), which may also set shared memory + base on Windows. */ static MYSQL *mysql_client_init(MYSQL* con) { - MYSQL* res = mysql_init(con); - #ifdef HAVE_SMEM - if (res && shared_memory_base_name) - mysql_options(res, MYSQL_SHARED_MEMORY_BASE_NAME, shared_memory_base_name); - #endif - return res; + MYSQL* res = mysql_init(con); +#ifdef HAVE_SMEM + if (res && shared_memory_base_name) + mysql_options(res, MYSQL_SHARED_MEMORY_BASE_NAME, shared_memory_base_name); +#endif + if (res && non_blocking_api_enabled) + mysql_options(res, MYSQL_OPT_NONBLOCK, 0); + if (opt_plugin_dir && *opt_plugin_dir) + mysql_options(res, MYSQL_PLUGIN_DIR, opt_plugin_dir); + + if (opt_default_auth && *opt_default_auth) + mysql_options(res, MYSQL_DEFAULT_AUTH, opt_default_auth); + return res; } /* -Disable direct calls of mysql_init, as it disregards shared memory base. + Disable direct calls of mysql_init, as it disregards shared memory base. */ #define mysql_init(A) Please use mysql_client_init instead of mysql_init @@ -246,120 +270,125 @@ Disable direct calls of mysql_init, as it disregards shared memory base. static my_bool check_have_innodb(MYSQL *conn) { - MYSQL_RES *res; - MYSQL_ROW row; - int rc; - my_bool result; - - rc= mysql_query(conn, "show variables like 'have_innodb'"); - myquery(rc); - res= mysql_use_result(conn); - DIE_UNLESS(res); - - row= mysql_fetch_row(res); - DIE_UNLESS(row); - - result= strcmp(row[1], "YES") == 0; - mysql_free_result(res); - return result; + MYSQL_RES *res; + MYSQL_ROW row; + int rc; + my_bool result; + + rc= mysql_query(conn, "show variables like 'have_innodb'"); + myquery(rc); + res= mysql_use_result(conn); + DIE_UNLESS(res); + + row= mysql_fetch_row(res); + DIE_UNLESS(row); + + result= strcmp(row[1], "YES") == 0; + mysql_free_result(res); + return result; } /* -This is to be what mysql_query() is for mysql_real_query(), for -mysql_simple_prepare(): a variant without the 'length' parameter. + This is to be what mysql_query() is for mysql_real_query(), for + mysql_simple_prepare(): a variant without the 'length' parameter. */ static MYSQL_STMT *STDCALL mysql_simple_prepare(MYSQL *mysql_arg, const char *query) { - MYSQL_STMT *stmt= mysql_stmt_init(mysql_arg); - if (stmt && mysql_stmt_prepare(stmt, query, (uint) strlen(query))) - { - mysql_stmt_close(stmt); - return 0; - } - return stmt; + MYSQL_STMT *stmt= mysql_stmt_init(mysql_arg); + if (stmt && mysql_stmt_prepare(stmt, query, (uint) strlen(query))) + { + mysql_stmt_close(stmt); + return 0; + } + return stmt; } /** -Connect to the server with options given by arguments to this application, -stored in global variables opt_host, opt_user, opt_password, opt_db, -opt_port and opt_unix_socket. + Connect to the server with options given by arguments to this application, + stored in global variables opt_host, opt_user, opt_password, opt_db, + opt_port and opt_unix_socket. -@param flag[in] client_flag passed on to mysql_real_connect -@param protocol[in] MYSQL_PROTOCOL_* to use for this connection -@param auto_reconnect[in] set to 1 for auto reconnect + @param flag[in] client_flag passed on to mysql_real_connect + @param protocol[in] MYSQL_PROTOCOL_* to use for this connection + @param auto_reconnect[in] set to 1 for auto reconnect -@return pointer to initialized and connected MYSQL object + @return pointer to initialized and connected MYSQL object */ static MYSQL* client_connect(ulong flag, uint protocol, my_bool auto_reconnect) { - MYSQL* mysql; - int rc; - static char query[MAX_TEST_QUERY_LENGTH]; - myheader_r("client_connect"); - - if (!opt_silent) - fprintf(stdout, "\n Establishing a connection to '%s' ...", - opt_host ? opt_host : ""); - - if (!(mysql= mysql_client_init(NULL))) - { - opt_silent= 0; - myerror("mysql_client_init() failed"); - exit(1); - } - /* enable local infile, in non-binary builds often disabled by default */ - mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0); - mysql_options(mysql, MYSQL_OPT_PROTOCOL, &protocol); - - if (!(mysql_real_connect(mysql, opt_host, opt_user, - opt_password, opt_db ? opt_db:"test", opt_port, - opt_unix_socket, flag))) - { - opt_silent= 0; - myerror("connection failed"); - mysql_close(mysql); - fprintf(stdout, "\n Check the connection options using --help or -?\n"); - exit(1); - } - mysql->reconnect= auto_reconnect; - - if (!opt_silent) - fprintf(stdout, "OK"); - - /* set AUTOCOMMIT to ON*/ - mysql_autocommit(mysql, TRUE); - - if (!opt_silent) - { - fprintf(stdout, "\nConnected to MySQL server version: %s (%lu)\n", - mysql_get_server_info(mysql), - (ulong) mysql_get_server_version(mysql)); - fprintf(stdout, "\n Creating a test database '%s' ...", current_db); - } - strxmov(query, "CREATE DATABASE IF NOT EXISTS ", current_db, NullS); - - rc= mysql_query(mysql, query); - myquery(rc); - - strxmov(query, "USE ", current_db, NullS); - rc= mysql_query(mysql, query); - myquery(rc); - have_innodb= check_have_innodb(mysql); - - if (!opt_silent) - fprintf(stdout, "OK\n"); - - return mysql; + MYSQL* mysql; + int rc; + static char query[MAX_TEST_QUERY_LENGTH]; + myheader_r("client_connect"); + + if (!opt_silent) + fprintf(stdout, "\n Establishing a connection to '%s' ...", + opt_host ? opt_host : ""); + + if (!(mysql= mysql_client_init(NULL))) + { + opt_silent= 0; + myerror("mysql_client_init() failed"); + exit(1); + } + /* enable local infile, in non-binary builds often disabled by default */ + mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0); + mysql_options(mysql, MYSQL_OPT_PROTOCOL, &protocol); + if (opt_plugin_dir && *opt_plugin_dir) + mysql_options(mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir); + + if (opt_default_auth && *opt_default_auth) + mysql_options(mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + + if (!(mysql_real_connect(mysql, opt_host, opt_user, + opt_password, opt_db ? opt_db:"test", opt_port, + opt_unix_socket, flag))) + { + opt_silent= 0; + myerror("connection failed"); + mysql_close(mysql); + fprintf(stdout, "\n Check the connection options using --help or -?\n"); + exit(1); + } + mysql->reconnect= auto_reconnect; + + if (!opt_silent) + fprintf(stdout, "OK"); + + /* set AUTOCOMMIT to ON*/ + mysql_autocommit(mysql, TRUE); + + if (!opt_silent) + { + fprintf(stdout, "\nConnected to MySQL server version: %s (%lu)\n", + mysql_get_server_info(mysql), + (ulong) mysql_get_server_version(mysql)); + fprintf(stdout, "\n Creating a test database '%s' ...", current_db); + } + strxmov(query, "CREATE DATABASE IF NOT EXISTS ", current_db, NullS); + + rc= mysql_query(mysql, query); + myquery(rc); + + strxmov(query, "USE ", current_db, NullS); + rc= mysql_query(mysql, query); + myquery(rc); + have_innodb= check_have_innodb(mysql); + + if (!opt_silent) + fprintf(stdout, "OK\n"); + + return mysql; } /* Close the connection */ -static void client_disconnect(MYSQL* mysql, my_bool drop_db) +static void client_disconnect(MYSQL* mysql) { static char query[MAX_TEST_QUERY_LENGTH]; @@ -367,7 +396,7 @@ static void client_disconnect(MYSQL* mysql, my_bool drop_db) if (mysql) { - if (drop_db) + if (opt_drop_db) { if (!opt_silent) fprintf(stdout, "\n dropping the test database '%s' ...", current_db); @@ -391,21 +420,21 @@ static void client_disconnect(MYSQL* mysql, my_bool drop_db) static void my_print_dashes(MYSQL_RES *result) { - MYSQL_FIELD *field; - unsigned int i, j; - - mysql_field_seek(result, 0); - fputc('\t', stdout); - fputc('+', stdout); - - for(i= 0; i< mysql_num_fields(result); i++) - { - field= mysql_fetch_field(result); - for(j= 0; j < field->max_length+2; j++) - fputc('-', stdout); - fputc('+', stdout); - } - fputc('\n', stdout); + MYSQL_FIELD *field; + unsigned int i, j; + + mysql_field_seek(result, 0); + fputc('\t', stdout); + fputc('+', stdout); + + for(i= 0; i< mysql_num_fields(result); i++) + { + field= mysql_fetch_field(result); + for(j= 0; j < field->max_length+2; j++) + fputc('-', stdout); + fputc('+', stdout); + } + fputc('\n', stdout); } @@ -413,47 +442,47 @@ static void my_print_dashes(MYSQL_RES *result) static void my_print_result_metadata(MYSQL_RES *result) { - MYSQL_FIELD *field; - unsigned int i, j; - unsigned int field_count; - - mysql_field_seek(result, 0); - if (!opt_silent) - { - fputc('\n', stdout); - fputc('\n', stdout); - } - - field_count= mysql_num_fields(result); - for(i= 0; i< field_count; i++) - { - field= mysql_fetch_field(result); - j= strlen(field->name); - if (j < field->max_length) - j= field->max_length; - if (j < 4 && !IS_NOT_NULL(field->flags)) - j= 4; - field->max_length= j; - } - if (!opt_silent) - { - my_print_dashes(result); - fputc('\t', stdout); - fputc('|', stdout); - } - - mysql_field_seek(result, 0); - for(i= 0; i< field_count; i++) - { - field= mysql_fetch_field(result); - if (!opt_silent) - fprintf(stdout, " %-*s |", (int) field->max_length, field->name); - } - if (!opt_silent) - { - fputc('\n', stdout); - my_print_dashes(result); - } + MYSQL_FIELD *field; + unsigned int i, j; + unsigned int field_count; + + mysql_field_seek(result, 0); + if (!opt_silent) + { + fputc('\n', stdout); + fputc('\n', stdout); + } + + field_count= mysql_num_fields(result); + for(i= 0; i< field_count; i++) + { + field= mysql_fetch_field(result); + j= strlen(field->name); + if (j < field->max_length) + j= field->max_length; + if (j < 4 && !IS_NOT_NULL(field->flags)) + j= 4; + field->max_length= j; + } + if (!opt_silent) + { + my_print_dashes(result); + fputc('\t', stdout); + fputc('|', stdout); + } + + mysql_field_seek(result, 0); + for(i= 0; i< field_count; i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + fprintf(stdout, " %-*s |", (int) field->max_length, field->name); + } + if (!opt_silent) + { + fputc('\n', stdout); + my_print_dashes(result); + } } @@ -461,72 +490,72 @@ static void my_print_result_metadata(MYSQL_RES *result) static int my_process_result_set(MYSQL_RES *result) { - MYSQL_ROW row; - MYSQL_FIELD *field; - unsigned int i; - unsigned int row_count= 0; - - if (!result) - return 0; - - my_print_result_metadata(result); - - while ((row= mysql_fetch_row(result)) != NULL) - { - mysql_field_seek(result, 0); - if (!opt_silent) - { - fputc('\t', stdout); - fputc('|', stdout); - } - - for(i= 0; i< mysql_num_fields(result); i++) - { - field= mysql_fetch_field(result); - if (!opt_silent) - { - if (row[i] == NULL) - fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); - else if (IS_NUM(field->type)) - fprintf(stdout, " %*s |", (int) field->max_length, row[i]); - else - fprintf(stdout, " %-*s |", (int) field->max_length, row[i]); - } - } - if (!opt_silent) - { - fputc('\t', stdout); - fputc('\n', stdout); - } - row_count++; - } - if (!opt_silent) - { - if (row_count) - my_print_dashes(result); - - if (mysql_errno(mysql) != 0) - fprintf(stderr, "\n\tmysql_fetch_row() failed\n"); - else - fprintf(stdout, "\n\t%d %s returned\n", row_count, - row_count == 1 ? "row" : "rows"); - } - return row_count; + MYSQL_ROW row; + MYSQL_FIELD *field; + unsigned int i; + unsigned int row_count= 0; + + if (!result) + return 0; + + my_print_result_metadata(result); + + while ((row= mysql_fetch_row(result)) != NULL) + { + mysql_field_seek(result, 0); + if (!opt_silent) + { + fputc('\t', stdout); + fputc('|', stdout); + } + + for(i= 0; i< mysql_num_fields(result); i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + { + if (row[i] == NULL) + fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); + else if (IS_NUM(field->type)) + fprintf(stdout, " %*s |", (int) field->max_length, row[i]); + else + fprintf(stdout, " %-*s |", (int) field->max_length, row[i]); + } + } + if (!opt_silent) + { + fputc('\t', stdout); + fputc('\n', stdout); + } + row_count++; + } + if (!opt_silent) + { + if (row_count) + my_print_dashes(result); + + if (mysql_errno(mysql) != 0) + fprintf(stderr, "\n\tmysql_fetch_row() failed\n"); + else + fprintf(stdout, "\n\t%d %s returned\n", row_count, + row_count == 1 ? "row" : "rows"); + } + return row_count; } static int my_process_result(MYSQL *mysql_arg) { - MYSQL_RES *result; - int row_count; + MYSQL_RES *result; + int row_count; - if (!(result= mysql_store_result(mysql_arg))) - return 0; + if (!(result= mysql_store_result(mysql_arg))) + return 0; - row_count= my_process_result_set(result); + row_count= my_process_result_set(result); - mysql_free_result(result); - return row_count; + mysql_free_result(result); + return row_count; } @@ -537,247 +566,270 @@ static int my_process_result(MYSQL *mysql_arg) static int my_process_stmt_result(MYSQL_STMT *stmt) { - int field_count; - int row_count= 0; - MYSQL_BIND buffer[MAX_RES_FIELDS]; - MYSQL_FIELD *field; - MYSQL_RES *result; - char data[MAX_RES_FIELDS][MAX_FIELD_DATA_SIZE]; - ulong length[MAX_RES_FIELDS]; - my_bool is_null[MAX_RES_FIELDS]; - int rc, i; - - if (!(result= mysql_stmt_result_metadata(stmt))) /* No meta info */ - { - while (!mysql_stmt_fetch(stmt)) - row_count++; - return row_count; - } + int field_count; + int row_count= 0; + MYSQL_BIND buffer[MAX_RES_FIELDS]; + MYSQL_FIELD *field; + MYSQL_RES *result; + char data[MAX_RES_FIELDS][MAX_FIELD_DATA_SIZE]; + ulong length[MAX_RES_FIELDS]; + my_bool is_null[MAX_RES_FIELDS]; + int rc, i; + + if (!(result= mysql_stmt_result_metadata(stmt))) /* No meta info */ + { + while (!mysql_stmt_fetch(stmt)) + row_count++; + return row_count; + } + + field_count= min(mysql_num_fields(result), MAX_RES_FIELDS); + + bzero((char*) buffer, sizeof(buffer)); + bzero((char*) length, sizeof(length)); + bzero((char*) is_null, sizeof(is_null)); + + for(i= 0; i < field_count; i++) + { + buffer[i].buffer_type= MYSQL_TYPE_STRING; + buffer[i].buffer_length= MAX_FIELD_DATA_SIZE; + buffer[i].length= &length[i]; + buffer[i].buffer= (void *) data[i]; + buffer[i].is_null= &is_null[i]; + } + + rc= mysql_stmt_bind_result(stmt, buffer); + check_execute(stmt, rc); + + rc= 1; + mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc); + rc= mysql_stmt_store_result(stmt); + check_execute(stmt, rc); + my_print_result_metadata(result); + + mysql_field_seek(result, 0); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + if (!opt_silent) + { + fputc('\t', stdout); + fputc('|', stdout); + } + mysql_field_seek(result, 0); + for (i= 0; i < field_count; i++) + { + field= mysql_fetch_field(result); + if (!opt_silent) + { + if (is_null[i]) + fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); + else if (length[i] == 0) + { + data[i][0]= '\0'; /* unmodified buffer */ + fprintf(stdout, " %*s |", (int) field->max_length, data[i]); + } + else if (IS_NUM(field->type)) + fprintf(stdout, " %*s |", (int) field->max_length, data[i]); + else + fprintf(stdout, " %-*s |", (int) field->max_length, data[i]); + } + } + if (!opt_silent) + { + fputc('\t', stdout); + fputc('\n', stdout); + } + row_count++; + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + if (!opt_silent) + { + if (row_count) + my_print_dashes(result); + fprintf(stdout, "\n\t%d %s returned\n", row_count, + row_count == 1 ? "row" : "rows"); + } + mysql_free_result(result); + return row_count; +} - field_count= min(mysql_num_fields(result), MAX_RES_FIELDS); - bzero((char*) buffer, sizeof(buffer)); - bzero((char*) length, sizeof(length)); - bzero((char*) is_null, sizeof(is_null)); +/* Prepare statement, execute, and process result set for given query */ - for(i= 0; i < field_count; i++) - { - buffer[i].buffer_type= MYSQL_TYPE_STRING; - buffer[i].buffer_length= MAX_FIELD_DATA_SIZE; - buffer[i].length= &length[i]; - buffer[i].buffer= (void *) data[i]; - buffer[i].is_null= &is_null[i]; - } +int my_stmt_result(const char *buff) +{ + MYSQL_STMT *stmt; + int row_count; + int rc; - rc= mysql_stmt_bind_result(stmt, buffer); - check_execute(stmt, rc); + if (!opt_silent) + fprintf(stdout, "\n\n %s", buff); + stmt= mysql_simple_prepare(mysql, buff); + check_stmt(stmt); - rc= 1; - mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*)&rc); - rc= mysql_stmt_store_result(stmt); - check_execute(stmt, rc); - my_print_result_metadata(result); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); - mysql_field_seek(result, 0); - while ((rc= mysql_stmt_fetch(stmt)) == 0) - { - if (!opt_silent) - { - fputc('\t', stdout); - fputc('|', stdout); - } - mysql_field_seek(result, 0); - for (i= 0; i < field_count; i++) - { - field= mysql_fetch_field(result); - if (!opt_silent) - { - if (is_null[i]) - fprintf(stdout, " %-*s |", (int) field->max_length, "NULL"); - else if (length[i] == 0) - { - data[i][0]= '\0'; /* unmodified buffer */ - fprintf(stdout, " %*s |", (int) field->max_length, data[i]); - } - else if (IS_NUM(field->type)) - fprintf(stdout, " %*s |", (int) field->max_length, data[i]); - else - fprintf(stdout, " %-*s |", (int) field->max_length, data[i]); - } - } - if (!opt_silent) - { - fputc('\t', stdout); - fputc('\n', stdout); - } - row_count++; - } - DIE_UNLESS(rc == MYSQL_NO_DATA); - if (!opt_silent) - { - if (row_count) - my_print_dashes(result); - fprintf(stdout, "\n\t%d %s returned\n", row_count, - row_count == 1 ? "row" : "rows"); - } - mysql_free_result(result); - return row_count; -} + row_count= my_process_stmt_result(stmt); + mysql_stmt_close(stmt); + return row_count; +} -/* Prepare statement, execute, and process result set for given query */ +/* Print the total number of warnings and the warnings themselves. */ -int my_stmt_result(const char *buff) +void my_process_warnings(MYSQL *conn, unsigned expected_warning_count) { - MYSQL_STMT *stmt; - int row_count; - int rc; + MYSQL_RES *result; + int rc; - if (!opt_silent) - fprintf(stdout, "\n\n %s", buff); - stmt= mysql_simple_prepare(mysql, buff); - check_stmt(stmt); + if (!opt_silent) + fprintf(stdout, "\n total warnings: %u (expected: %u)\n", + mysql_warning_count(conn), expected_warning_count); + + DIE_UNLESS(mysql_warning_count(mysql) == expected_warning_count); - rc= mysql_stmt_execute(stmt); - check_execute(stmt, rc); + rc= mysql_query(conn, "SHOW WARNINGS"); + DIE_UNLESS(rc == 0); - row_count= my_process_stmt_result(stmt); - mysql_stmt_close(stmt); + result= mysql_store_result(conn); + mytest(result); - return row_count; + rc= my_process_result_set(result); + mysql_free_result(result); } /* Utility function to verify a particular column data */ static void verify_col_data(const char *table, const char *col, -const char *exp_data) + const char *exp_data) { - static char query[MAX_TEST_QUERY_LENGTH]; - MYSQL_RES *result; - MYSQL_ROW row; - int rc, field= 1; - - if (table && col) - { - strxmov(query, "SELECT ", col, " FROM ", table, " LIMIT 1", NullS); - if (!opt_silent) - fprintf(stdout, "\n %s", query); - rc= mysql_query(mysql, query); - myquery(rc); - - field= 0; - } - - result= mysql_use_result(mysql); - mytest(result); - - if (!(row= mysql_fetch_row(result)) || !row[field]) - { - fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); - exit(1); - } - if (strcmp(row[field], exp_data)) - { - fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", - row[field], exp_data); - DIE_UNLESS(FALSE); - } - mysql_free_result(result); + static char query[MAX_TEST_QUERY_LENGTH]; + MYSQL_RES *result; + MYSQL_ROW row; + int rc, field= 1; + + if (table && col) + { + strxmov(query, "SELECT ", col, " FROM ", table, " LIMIT 1", NullS); + if (!opt_silent) + fprintf(stdout, "\n %s", query); + rc= mysql_query(mysql, query); + myquery(rc); + + field= 0; + } + + result= mysql_use_result(mysql); + mytest(result); + + if (!(row= mysql_fetch_row(result)) || !row[field]) + { + fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); + exit(1); + } + if (strcmp(row[field], exp_data)) + { + fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", + row[field], exp_data); + DIE_UNLESS(FALSE); + } + mysql_free_result(result); } /* Utility function to verify the field members */ -#define verify_prepare_field(result,no,name,org_name,type,table, \ -org_table,db,length,def) \ -do_verify_prepare_field((result),(no),(name),(org_name),(type), \ -(table),(org_table),(db),(length),(def), \ -__FILE__, __LINE__) +#define verify_prepare_field(result,no,name,org_name,type,table,\ + org_table,db,length,def) \ + do_verify_prepare_field((result),(no),(name),(org_name),(type), \ + (table),(org_table),(db),(length),(def), \ + __FILE__, __LINE__) static void do_verify_prepare_field(MYSQL_RES *result, -unsigned int no, const char *name, -const char *org_name, -enum enum_field_types type, -const char *table, -const char *org_table, const char *db, -unsigned long length, const char *def, -const char *file, int line) + unsigned int no, const char *name, + const char *org_name, + enum enum_field_types type, + const char *table, + const char *org_table, const char *db, + unsigned long length, const char *def, + const char *file, int line) { - MYSQL_FIELD *field; - CHARSET_INFO *cs; - ulonglong expected_field_length; - - if (!(field= mysql_fetch_field_direct(result, no))) - { - fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); - exit(1); - } - cs= get_charset(field->charsetnr, 0); - DIE_UNLESS(cs); - if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32) - expected_field_length= UINT_MAX32; - if (!opt_silent) - { - fprintf(stdout, "\n field[%d]:", no); - fprintf(stdout, "\n name :`%s`\t(expected: `%s`)", field->name, name); - fprintf(stdout, "\n org_name :`%s`\t(expected: `%s`)", - field->org_name, org_name); - fprintf(stdout, "\n type :`%d`\t(expected: `%d`)", field->type, type); - if (table) - fprintf(stdout, "\n table :`%s`\t(expected: `%s`)", - field->table, table); - if (org_table) - fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)", - field->org_table, org_table); - fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db); - fprintf(stdout, "\n length :`%lu`\t(expected: `%llu`)", - field->length, expected_field_length); - fprintf(stdout, "\n maxlength:`%ld`", field->max_length); - fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr); - fprintf(stdout, "\n default :`%s`\t(expected: `%s`)", - field->def ? field->def : "(null)", def ? def: "(null)"); - fprintf(stdout, "\n"); - } - DIE_UNLESS(strcmp(field->name, name) == 0); - DIE_UNLESS(strcmp(field->org_name, org_name) == 0); - /* - XXX: silent column specification change works based on number of - bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even - for CHAR(2) column if its character set is multibyte. - VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would - expect. - */ - if (cs->mbmaxlen == 1) - { - if (field->type != type) - { - fprintf(stderr, - "Expected field type: %d, got type: %d in file %s, line %d\n", - (int) type, (int) field->type, file, line); - DIE_UNLESS(field->type == type); - } - } - if (table) - DIE_UNLESS(strcmp(field->table, table) == 0); - if (org_table) - DIE_UNLESS(strcmp(field->org_table, org_table) == 0); - DIE_UNLESS(strcmp(field->db, db) == 0); - /* - Character set should be taken into account for multibyte encodings, such - as utf8. Field length is calculated as number of characters * maximum - number of bytes a character can occupy. - */ - if (length && (field->length != expected_field_length)) - { - fflush(stdout); - fprintf(stderr, "Expected field length: %llu, got length: %lu\n", - expected_field_length, field->length); - fflush(stderr); - DIE_UNLESS(field->length == expected_field_length); - } - if (def) - DIE_UNLESS(strcmp(field->def, def) == 0); + MYSQL_FIELD *field; + CHARSET_INFO *cs; + ulonglong expected_field_length; + + if (!(field= mysql_fetch_field_direct(result, no))) + { + fprintf(stdout, "\n *** ERROR: FAILED TO GET THE RESULT ***"); + exit(1); + } + cs= get_charset(field->charsetnr, 0); + DIE_UNLESS(cs); + if ((expected_field_length= length * cs->mbmaxlen) > UINT_MAX32) + expected_field_length= UINT_MAX32; + if (!opt_silent) + { + fprintf(stdout, "\n field[%d]:", no); + fprintf(stdout, "\n name :`%s`\t(expected: `%s`)", field->name, name); + fprintf(stdout, "\n org_name :`%s`\t(expected: `%s`)", + field->org_name, org_name); + fprintf(stdout, "\n type :`%d`\t(expected: `%d`)", field->type, type); + if (table) + fprintf(stdout, "\n table :`%s`\t(expected: `%s`)", + field->table, table); + if (org_table) + fprintf(stdout, "\n org_table:`%s`\t(expected: `%s`)", + field->org_table, org_table); + fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db); + fprintf(stdout, "\n length :`%lu`\t(expected: `%llu`)", + field->length, expected_field_length); + fprintf(stdout, "\n maxlength:`%ld`", field->max_length); + fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr); + fprintf(stdout, "\n default :`%s`\t(expected: `%s`)", + field->def ? field->def : "(null)", def ? def: "(null)"); + fprintf(stdout, "\n"); + } + DIE_UNLESS(strcmp(field->name, name) == 0); + DIE_UNLESS(strcmp(field->org_name, org_name) == 0); + /* + XXX: silent column specification change works based on number of + bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even + for CHAR(2) column if its character set is multibyte. + VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would + expect. + */ + if (cs->mbmaxlen == 1) + { + if (field->type != type) + { + fprintf(stderr, + "Expected field type: %d, got type: %d in file %s, line %d\n", + (int) type, (int) field->type, file, line); + DIE_UNLESS(field->type == type); + } + } + if (table) + DIE_UNLESS(strcmp(field->table, table) == 0); + if (org_table) + DIE_UNLESS(strcmp(field->org_table, org_table) == 0); + DIE_UNLESS(strcmp(field->db, db) == 0); + /* + Character set should be taken into account for multibyte encodings, such + as utf8. Field length is calculated as number of characters * maximum + number of bytes a character can occupy. + */ + if (length && (field->length != expected_field_length)) + { + fflush(stdout); + fprintf(stderr, "Expected field length: %llu, got length: %lu\n", + expected_field_length, field->length); + fflush(stderr); + DIE_UNLESS(field->length == expected_field_length); + } + if (def) + DIE_UNLESS(strcmp(field->def, def) == 0); } @@ -785,11 +837,11 @@ const char *file, int line) static void verify_param_count(MYSQL_STMT *stmt, long exp_count) { - long param_count= mysql_stmt_param_count(stmt); - if (!opt_silent) - fprintf(stdout, "\n total parameters in stmt: `%ld` (expected: `%ld`)", - param_count, exp_count); - DIE_UNLESS(param_count == exp_count); + long param_count= mysql_stmt_param_count(stmt); + if (!opt_silent) + fprintf(stdout, "\n total parameters in stmt: `%ld` (expected: `%ld`)", + param_count, exp_count); + DIE_UNLESS(param_count == exp_count); } @@ -797,11 +849,11 @@ static void verify_param_count(MYSQL_STMT *stmt, long exp_count) static void verify_st_affected_rows(MYSQL_STMT *stmt, ulonglong exp_count) { - ulonglong affected_rows= mysql_stmt_affected_rows(stmt); - if (!opt_silent) - fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", - (long) affected_rows, (long) exp_count); - DIE_UNLESS(affected_rows == exp_count); + ulonglong affected_rows= mysql_stmt_affected_rows(stmt); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + DIE_UNLESS(affected_rows == exp_count); } @@ -809,11 +861,11 @@ static void verify_st_affected_rows(MYSQL_STMT *stmt, ulonglong exp_count) static void verify_affected_rows(ulonglong exp_count) { - ulonglong affected_rows= mysql_affected_rows(mysql); - if (!opt_silent) - fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", - (long) affected_rows, (long) exp_count); - DIE_UNLESS(affected_rows == exp_count); + ulonglong affected_rows= mysql_affected_rows(mysql); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); + DIE_UNLESS(affected_rows == exp_count); } @@ -821,11 +873,11 @@ static void verify_affected_rows(ulonglong exp_count) static void verify_field_count(MYSQL_RES *result, uint exp_count) { - uint field_count= mysql_num_fields(result); - if (!opt_silent) - fprintf(stdout, "\n total fields in the result set: `%d` (expected: `%d`)", - field_count, exp_count); - DIE_UNLESS(field_count == exp_count); + uint field_count= mysql_num_fields(result); + if (!opt_silent) + fprintf(stdout, "\n total fields in the result set: `%d` (expected: `%d`)", + field_count, exp_count); + DIE_UNLESS(field_count == exp_count); } @@ -834,23 +886,23 @@ static void verify_field_count(MYSQL_RES *result, uint exp_count) #ifndef EMBEDDED_LIBRARY static void execute_prepare_query(const char *query, ulonglong exp_count) { - MYSQL_STMT *stmt; - ulonglong affected_rows; - int rc; + MYSQL_STMT *stmt; + ulonglong affected_rows; + int rc; - stmt= mysql_simple_prepare(mysql, query); - check_stmt(stmt); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); - rc= mysql_stmt_execute(stmt); - myquery(rc); + rc= mysql_stmt_execute(stmt); + myquery(rc); - affected_rows= mysql_stmt_affected_rows(stmt); - if (!opt_silent) - fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", - (long) affected_rows, (long) exp_count); + affected_rows= mysql_stmt_affected_rows(stmt); + if (!opt_silent) + fprintf(stdout, "\n total affected rows: `%ld` (expected: `%ld`)", + (long) affected_rows, (long) exp_count); - DIE_UNLESS(affected_rows == exp_count); - mysql_stmt_close(stmt); + DIE_UNLESS(affected_rows == exp_count); + mysql_stmt_close(stmt); } #endif @@ -1116,7 +1168,7 @@ static my_bool thread_query(const char *query) /* -Read and parse arguments and MySQL options from my.cnf + Read and parse arguments and MySQL options from my.cnf */ static const char *client_test_load_default_groups[]= @@ -1125,256 +1177,272 @@ static char **defaults_argv; static struct my_option client_test_long_options[] = { -{"basedir", 'b', "Basedir for tests.", &opt_basedir, - &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -{"count", 't', "Number of times test to be executed", &opt_count, - &opt_count, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, -{"database", 'D', "Database to use", &opt_db, &opt_db, - 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -{"debug", '#', "Output debug log", &default_dbug_option, - &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, -{"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, - 0, 0, 0, 0, 0}, -{"host", 'h', "Connect to host", &opt_host, &opt_host, - 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -{"password", 'p', - "Password to use when connecting to server. If password is not given it's asked from the tty.", - 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, -{"port", 'P', "Port number to use for connection or 0 for default to, in " - "order of preference, my.cnf, $MYSQL_TCP_PORT, " - #if MYSQL_PORT_DEFAULT == 0 - "/etc/services, " - #endif - "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - &opt_port, &opt_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -{"server-arg", 'A', "Send embedded server this as a parameter.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -{"show-tests", 'T', "Show all tests' names", 0, 0, 0, GET_NO_ARG, NO_ARG, - 0, 0, 0, 0, 0, 0}, -{"silent", 's', "Be more silent", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, - 0}, + {"basedir", 'b', "Basedir for tests.", &opt_basedir, + &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"count", 't', "Number of times test to be executed", &opt_count, + &opt_count, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, + {"database", 'D', "Database to use", &opt_db, &opt_db, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"do-not-drop-database", 'd', "Do not drop database while disconnecting", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"debug", '#', "Output debug log", &default_dbug_option, + &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, + 0, 0, 0, 0, 0}, + {"host", 'h', "Connect to host", &opt_host, &opt_host, + 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"password", 'p', + "Password to use when connecting to server. If password is not given it's asked from the tty.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"port", 'P', "Port number to use for connection or 0 for default to, in " + "order of preference, my.cnf, $MYSQL_TCP_PORT, " +#if MYSQL_PORT_DEFAULT == 0 + "/etc/services, " +#endif + "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", + &opt_port, &opt_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"server-arg", 'A', "Send embedded server this as a parameter.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"show-tests", 'T', "Show all tests' names", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, + {"silent", 's', "Be more silent", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, + 0}, #ifdef HAVE_SMEM -{"shared-memory-base-name", 'm', "Base name of shared memory.", - &shared_memory_base_name, (uchar**)&shared_memory_base_name, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"shared-memory-base-name", 'm', "Base name of shared memory.", + &shared_memory_base_name, (uchar**)&shared_memory_base_name, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif -{"socket", 'S', "Socket file to use for connection", - &opt_unix_socket, &opt_unix_socket, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -{"testcase", 'c', - "May disable some code when runs as mysql-test-run testcase.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"socket", 'S', "Socket file to use for connection", + &opt_unix_socket, &opt_unix_socket, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"testcase", 'c', + "May disable some code when runs as mysql-test-run testcase.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef DONT_ALLOW_USER_CHANGE -{"user", 'u', "User for login if not current user", &opt_user, - &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"user", 'u', "User for login if not current user", &opt_user, + &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif -{"vardir", 'v', "Data dir for tests.", &opt_vardir, - &opt_vardir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -{"getopt-ll-test", 'g', "Option for testing bug in getopt library", - &opt_getopt_ll_test, &opt_getopt_ll_test, 0, - GET_LL, REQUIRED_ARG, 0, 0, LONGLONG_MAX, 0, 0, 0}, -{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} + {"vardir", 'v', "Data dir for tests.", &opt_vardir, + &opt_vardir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"non-blocking-api", 'n', + "Use the non-blocking client API for communication.", + &non_blocking_api_enabled, &non_blocking_api_enabled, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"getopt-ll-test", 'g', "Option for testing bug in getopt library", + &opt_getopt_ll_test, &opt_getopt_ll_test, 0, + GET_LL, REQUIRED_ARG, 0, 0, LONGLONG_MAX, 0, 0, 0}, + {"plugin_dir", 0, "Directory for client-side plugins.", + &opt_plugin_dir, &opt_plugin_dir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"default_auth", 0, "Default authentication client-side plugin to use.", + &opt_default_auth, &opt_default_auth, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; static void usage(void) { -/* show the usage string when the user asks for this */ - putc('\n', stdout); - printf("%s Ver %s Distrib %s, for %s (%s)\n", - my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); - puts("By Monty, Venu, Kent and others\n"); - printf("\ + /* show the usage string when the user asks for this */ + putc('\n', stdout); + printf("%s Ver %s Distrib %s, for %s (%s)\n", + my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); + puts("By Monty, Venu, Kent and others\n"); + printf("\ Copyright (C) 2002-2004 MySQL AB\n\ This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ and you are welcome to modify and redistribute it under the GPL license\n"); - printf("Usage: %s [OPTIONS] [TESTNAME1 TESTNAME2...]\n", my_progname); - my_print_help(client_test_long_options); - print_defaults("my", client_test_load_default_groups); - my_print_variables(client_test_long_options); + printf("Usage: %s [OPTIONS] [TESTNAME1 TESTNAME2...]\n", my_progname); + my_print_help(client_test_long_options); + print_defaults("my", client_test_load_default_groups); + my_print_variables(client_test_long_options); } - static struct my_tests_st *get_my_tests(); /* To be defined in main .c file */ static struct my_tests_st *my_testlist= 0; static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), -char *argument) + char *argument) { - switch (optid) { - case '#': - DBUG_PUSH(argument ? argument : default_dbug_option); - break; - case 'c': - opt_testcase = 1; - break; - case 'p': - if (argument) - { - char *start=argument; - my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); - opt_password= my_strdup(argument, MYF(MY_FAE)); - while (*argument) *argument++= 'x'; /* Destroy argument */ - if (*start) - start[1]=0; - } - else - tty_password= 1; - break; - case 's': - if (argument == disabled_my_option) - opt_silent= 0; - else - opt_silent++; - break; - case 'A': - /* - When the embedded server is being tested, the test suite needs to be - able to pass command-line arguments to the embedded server so it can - locate the language files and data directory. The test suite - (mysql-test-run) never uses config files, just command-line options. - */ - if (!embedded_server_arg_count) - { - embedded_server_arg_count= 1; - embedded_server_args[0]= (char*) ""; - } - if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || - !(embedded_server_args[embedded_server_arg_count++]= - my_strdup(argument, MYF(MY_FAE)))) - { - DIE("Can't use server argument"); - } - break; - case 'T': - { - struct my_tests_st *fptr; + switch (optid) { + case '#': + DBUG_PUSH(argument ? argument : default_dbug_option); + break; + case 'c': + opt_testcase = 1; + break; + case 'p': + if (argument) + { + char *start=argument; + my_free(opt_password); + opt_password= my_strdup(argument, MYF(MY_FAE)); + while (*argument) *argument++= 'x'; /* Destroy argument */ + if (*start) + start[1]=0; + } + else + tty_password= 1; + break; + case 's': + if (argument == disabled_my_option) + opt_silent= 0; + else + opt_silent++; + break; + case 'd': + opt_drop_db= 0; + break; + case 'A': + /* + When the embedded server is being tested, the test suite needs to be + able to pass command-line arguments to the embedded server so it can + locate the language files and data directory. The test suite + (mysql-test-run) never uses config files, just command-line options. + */ + if (!embedded_server_arg_count) + { + embedded_server_arg_count= 1; + embedded_server_args[0]= (char*) ""; + } + if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || + !(embedded_server_args[embedded_server_arg_count++]= + my_strdup(argument, MYF(MY_FAE)))) + { + DIE("Can't use server argument"); + } + break; + case 'T': + { + struct my_tests_st *fptr; - printf("All possible test names:\n\n"); - for (fptr= my_testlist; fptr->name; fptr++) - printf("%s\n", fptr->name); - exit(0); - break; - } - case '?': - case 'I': /* Info */ - usage(); - exit(0); - break; - } - return 0; + printf("All possible test names:\n\n"); + for (fptr= my_testlist; fptr->name; fptr++) + printf("%s\n", fptr->name); + exit(0); + break; + } + case '?': + case 'I': /* Info */ + usage(); + exit(0); + break; + } + return 0; } static void get_options(int *argc, char ***argv) { - int ho_error; + int ho_error; - if ((ho_error= handle_options(argc, argv, client_test_long_options, - get_one_option))) - exit(ho_error); + if ((ho_error= handle_options(argc, argv, client_test_long_options, + get_one_option))) + exit(ho_error); - if (tty_password) - opt_password= get_tty_password(NullS); - return; + if (tty_password) + opt_password= get_tty_password(NullS); + return; } /* -Print the test output on successful execution before exiting + Print the test output on successful execution before exiting */ static void print_test_output() { - if (opt_silent < 3) - { - fprintf(stdout, "\n\n"); - fprintf(stdout, "All '%d' tests were successful (in '%d' iterations)", - test_count-1, opt_count); - fprintf(stdout, "\n Total execution time: %g SECS", total_time); - if (opt_count > 1) - fprintf(stdout, " (Avg: %g SECS)", total_time/opt_count); - - fprintf(stdout, "\n\n!!! SUCCESS !!!\n"); - } + if (opt_silent < 3) + { + fprintf(stdout, "\n\n"); + fprintf(stdout, "All '%d' tests were successful (in '%d' iterations)", + test_count-1, opt_count); + fprintf(stdout, "\n Total execution time: %g SECS", total_time); + if (opt_count > 1) + fprintf(stdout, " (Avg: %g SECS)", total_time/opt_count); + + fprintf(stdout, "\n\n!!! SUCCESS !!!\n"); + } } /*************************************************************************** -main routine + main routine ***************************************************************************/ int main(int argc, char **argv) { - struct my_tests_st *fptr; - my_testlist= get_my_tests(); - - MY_INIT(argv[0]); - - load_defaults("my", client_test_load_default_groups, &argc, &argv); - defaults_argv= argv; - get_options(&argc, &argv); - - if (mysql_server_init(embedded_server_arg_count, - embedded_server_args, - (char**) embedded_server_groups)) - DIE("Can't initialize MySQL server"); - - /* connect to server with no flags, default protocol, auto reconnect true */ - mysql= client_connect(0, MYSQL_PROTOCOL_DEFAULT, 1); - - total_time= 0; - for (iter_count= 1; iter_count <= opt_count; iter_count++) - { - /* Start of tests */ - test_count= 1; - start_time= time((time_t *)0); - if (!argc) - { - for (fptr= my_testlist; fptr->name; fptr++) - (*fptr->function)(); - } - else - { - for ( ; *argv ; argv++) - { - for (fptr= my_testlist; fptr->name; fptr++) - { - if (!strcmp(fptr->name, *argv)) - { - (*fptr->function)(); - break; - } - } - if (!fptr->name) - { - fprintf(stderr, "\n\nGiven test not found: '%s'\n", *argv); - fprintf(stderr, "See legal test names with %s -T\n\nAborting!\n", - my_progname); - client_disconnect(mysql, 1); - free_defaults(defaults_argv); - exit(1); - } - } - } - - end_time= time((time_t *)0); - total_time+= difftime(end_time, start_time); - - /* End of tests */ - } - - client_disconnect(mysql, 1); /* disconnect from server */ - - free_defaults(defaults_argv); - print_test_output(); - - while (embedded_server_arg_count > 1) - my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); - - mysql_server_end(); - - my_end(0); - - exit(0); + struct my_tests_st *fptr; + my_testlist= get_my_tests(); + + MY_INIT(argv[0]); + + if (load_defaults("my", client_test_load_default_groups, &argc, &argv)) + exit(1); + + defaults_argv= argv; + get_options(&argc, &argv); + + if (mysql_server_init(embedded_server_arg_count, + embedded_server_args, + (char**) embedded_server_groups)) + DIE("Can't initialize MySQL server"); + + /* connect to server with no flags, default protocol, auto reconnect true */ + mysql= client_connect(0, MYSQL_PROTOCOL_DEFAULT, 1); + + total_time= 0; + for (iter_count= 1; iter_count <= opt_count; iter_count++) + { + /* Start of tests */ + test_count= 1; + start_time= time((time_t *)0); + if (!argc) + { + for (fptr= my_testlist; fptr->name; fptr++) + (*fptr->function)(); + } + else + { + for ( ; *argv ; argv++) + { + for (fptr= my_testlist; fptr->name; fptr++) + { + if (!strcmp(fptr->name, *argv)) + { + (*fptr->function)(); + break; + } + } + if (!fptr->name) + { + fprintf(stderr, "\n\nGiven test not found: '%s'\n", *argv); + fprintf(stderr, "See legal test names with %s -T\n\nAborting!\n", + my_progname); + client_disconnect(mysql); + free_defaults(defaults_argv); + exit(1); + } + } + } + + end_time= time((time_t *)0); + total_time+= difftime(end_time, start_time); + + /* End of tests */ + } + + client_disconnect(mysql); /* disconnect from server */ + + free_defaults(defaults_argv); + print_test_output(); + + while (embedded_server_arg_count > 1) + my_free(embedded_server_args[--embedded_server_arg_count]); + + mysql_server_end(); + + my_end(0); + + exit(0); } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 650c8858bb9..7ec91636d26 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -26,6 +26,7 @@ DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH. */ + /* The fw.c file includes all the mysql_client_test framework; this file contains only the actual tests, plus the list of test functions to call. @@ -356,6 +357,7 @@ static void test_prepare_insert_update() myquery(rc); } + /* Test simple prepares of all DML statements */ static void test_prepare_simple() @@ -425,6 +427,817 @@ static void test_prepare_simple() myquery(rc); } +/************************************************************************/ + +#define FILE_PATH_SIZE 4096 + +char mct_log_file_path[FILE_PATH_SIZE]; +FILE *mct_log_file= NULL; + +void mct_start_logging(const char *test_case_name) +{ + const char *tmp_dir= getenv("MYSQL_TMP_DIR"); + + if (!tmp_dir) + { + printf("Warning: MYSQL_TMP_DIR is not set. Logging is disabled.\n"); + return; + } + + if (mct_log_file) + { + printf("Warning: can not start logging for test case '%s' " + "because log is already open\n", + (const char *) test_case_name); + return; + } + + /* + Path is: <tmp_dir>/<test_case_name>.out.log + 10 is length of '/' + '.out.log' + \0 + */ + + if (strlen(tmp_dir) + strlen(test_case_name) + 10 > FILE_PATH_SIZE) + { + printf("Warning: MYSQL_TMP_DIR is too long. Logging is disabled.\n"); + return; + } + + my_snprintf(mct_log_file_path, FILE_PATH_SIZE, + "%s/%s.out.log", + (const char *) tmp_dir, + (const char *) test_case_name); + + mct_log_file= my_fopen(mct_log_file_path, O_WRONLY | O_BINARY, MYF(MY_WME)); + + if (!mct_log_file) + { + printf("Warning: can not open log file (%s): %s. Logging is disabled.\n", + (const char *) mct_log_file_path, + (const char *) strerror(errno)); + return; + } +} + +void mct_log(const char *format, ...) +{ + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + + if (mct_log_file) + { + va_list args; + va_start(args, format); + vfprintf(mct_log_file, format, args); + va_end(args); + } +} + +void mct_close_log() +{ + if (!mct_log_file) + return; + + my_fclose(mct_log_file, MYF(0)); + mct_log_file= NULL; +} + +#define WL4435_NUM_PARAMS 10 +#define WL4435_STRING_SIZE 30 + +static void test_wl4435() +{ + MYSQL_STMT *stmt; + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + char str_data[20][WL4435_STRING_SIZE]; + double dbl_data[20]; + char dec_data[20][WL4435_STRING_SIZE]; + int int_data[20]; + ulong str_length= WL4435_STRING_SIZE; + my_bool is_null; + MYSQL_BIND ps_params[WL4435_NUM_PARAMS]; + + int exec_counter; + + myheader("test_wl4435"); + mct_start_logging("test_wl4435"); + + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p2"); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS t2"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t1(a1 INT, a2 CHAR(32), " + " a3 DOUBLE(4, 2), a4 DECIMAL(3, 1))"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t2(b0 INT, b1 INT, b2 CHAR(32), " + " b3 DOUBLE(4, 2), b4 DECIMAL(3, 1))"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES" + "(1, '11', 12.34, 56.7), " + "(2, '12', 56.78, 90.1), " + "(3, '13', 23.45, 67.8)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t2 VALUES" + "(100, 10, '110', 70.70, 10.1), " + "(200, 20, '120', 80.80, 20.2), " + "(300, 30, '130', 90.90, 30.3)"); + myquery(rc); + + rc= mysql_query(mysql, + "CREATE PROCEDURE p1(" + " IN v0 INT, " + " OUT v_str_1 CHAR(32), " + " OUT v_dbl_1 DOUBLE(4, 2), " + " OUT v_dec_1 DECIMAL(6, 3), " + " OUT v_int_1 INT, " + " IN v1 INT, " + " INOUT v_str_2 CHAR(64), " + " INOUT v_dbl_2 DOUBLE(5, 3), " + " INOUT v_dec_2 DECIMAL(7, 4), " + " INOUT v_int_2 INT)" + "BEGIN " + " SET v0 = -1; " + " SET v1 = -1; " + " SET v_str_1 = 'test_1'; " + " SET v_dbl_1 = 12.34; " + " SET v_dec_1 = 567.891; " + " SET v_int_1 = 2345; " + " SET v_str_2 = 'test_2'; " + " SET v_dbl_2 = 67.891; " + " SET v_dec_2 = 234.6789; " + " SET v_int_2 = 6789; " + " SELECT * FROM t1; " + " SELECT * FROM t2; " + "END"); + myquery(rc); + + rc= mysql_query(mysql, + "CREATE PROCEDURE p2(" + " IN i1 VARCHAR(255) CHARACTER SET koi8r, " + " OUT o1 VARCHAR(255) CHARACTER SET cp1251, " + " OUT o2 VARBINARY(255)) " + "BEGIN " + " SET o1 = i1; " + " SET o2 = i1; " + "END"); + myquery(rc); + + strmov(query, "CALL p1(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + /* Init PS-parameters. */ + + bzero((char *) ps_params, sizeof (ps_params)); + + /* - v0 -- INT */ + + ps_params[0].buffer_type= MYSQL_TYPE_LONG; + ps_params[0].buffer= (char *) &int_data[0]; + ps_params[0].length= 0; + ps_params[0].is_null= 0; + + /* - v_str_1 -- CHAR(32) */ + + ps_params[1].buffer_type= MYSQL_TYPE_STRING; + ps_params[1].buffer= (char *) str_data[0]; + ps_params[1].buffer_length= WL4435_STRING_SIZE; + ps_params[1].length= &str_length; + ps_params[1].is_null= 0; + + /* - v_dbl_1 -- DOUBLE */ + + ps_params[2].buffer_type= MYSQL_TYPE_DOUBLE; + ps_params[2].buffer= (char *) &dbl_data[0]; + ps_params[2].length= 0; + ps_params[2].is_null= 0; + + /* - v_dec_1 -- DECIMAL */ + + ps_params[3].buffer_type= MYSQL_TYPE_NEWDECIMAL; + ps_params[3].buffer= (char *) dec_data[0]; + ps_params[3].buffer_length= WL4435_STRING_SIZE; + ps_params[3].length= 0; + ps_params[3].is_null= 0; + + /* - v_int_1 -- INT */ + + ps_params[4].buffer_type= MYSQL_TYPE_LONG; + ps_params[4].buffer= (char *) &int_data[0]; + ps_params[4].length= 0; + ps_params[4].is_null= 0; + + /* - v1 -- INT */ + + ps_params[5].buffer_type= MYSQL_TYPE_LONG; + ps_params[5].buffer= (char *) &int_data[0]; + ps_params[5].length= 0; + ps_params[5].is_null= 0; + + /* - v_str_2 -- CHAR(32) */ + + ps_params[6].buffer_type= MYSQL_TYPE_STRING; + ps_params[6].buffer= (char *) str_data[0]; + ps_params[6].buffer_length= WL4435_STRING_SIZE; + ps_params[6].length= &str_length; + ps_params[6].is_null= 0; + + /* - v_dbl_2 -- DOUBLE */ + + ps_params[7].buffer_type= MYSQL_TYPE_DOUBLE; + ps_params[7].buffer= (char *) &dbl_data[0]; + ps_params[7].length= 0; + ps_params[7].is_null= 0; + + /* - v_dec_2 -- DECIMAL */ + + ps_params[8].buffer_type= MYSQL_TYPE_DECIMAL; + ps_params[8].buffer= (char *) dec_data[0]; + ps_params[8].buffer_length= WL4435_STRING_SIZE; + ps_params[8].length= 0; + ps_params[8].is_null= 0; + + /* - v_int_2 -- INT */ + + ps_params[9].buffer_type= MYSQL_TYPE_LONG; + ps_params[9].buffer= (char *) &int_data[0]; + ps_params[9].length= 0; + ps_params[9].is_null= 0; + + /* Bind parameters. */ + + rc= mysql_stmt_bind_param(stmt, ps_params); + + /* Execute! */ + + for (exec_counter= 0; exec_counter < 3; ++exec_counter) + { + int i; + int num_fields; + MYSQL_BIND *rs_bind; + + mct_log("\nexec_counter: %d\n", (int) exec_counter); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + while (1) + { + MYSQL_FIELD *fields; + + MYSQL_RES *rs_metadata= mysql_stmt_result_metadata(stmt); + + num_fields= mysql_stmt_field_count(stmt); + fields= mysql_fetch_fields(rs_metadata); + + rs_bind= (MYSQL_BIND *) malloc(sizeof (MYSQL_BIND) * num_fields); + bzero(rs_bind, sizeof (MYSQL_BIND) * num_fields); + + mct_log("num_fields: %d\n", (int) num_fields); + + for (i = 0; i < num_fields; ++i) + { + mct_log(" - %d: name: '%s'/'%s'; table: '%s'/'%s'; " + "db: '%s'; catalog: '%s'; length: %d; max_length: %d; " + "type: %d; decimals: %d\n", + (int) i, + (const char *) fields[i].name, + (const char *) fields[i].org_name, + (const char *) fields[i].table, + (const char *) fields[i].org_table, + (const char *) fields[i].db, + (const char *) fields[i].catalog, + (int) fields[i].length, + (int) fields[i].max_length, + (int) fields[i].type, + (int) fields[i].decimals); + + rs_bind[i].buffer_type= fields[i].type; + rs_bind[i].is_null= &is_null; + + switch (fields[i].type) + { + case MYSQL_TYPE_LONG: + rs_bind[i].buffer= (char *) &(int_data[i]); + rs_bind[i].buffer_length= sizeof (int_data); + break; + + case MYSQL_TYPE_STRING: + rs_bind[i].buffer= (char *) str_data[i]; + rs_bind[i].buffer_length= WL4435_STRING_SIZE; + rs_bind[i].length= &str_length; + break; + + case MYSQL_TYPE_DOUBLE: + rs_bind[i].buffer= (char *) &dbl_data[i]; + rs_bind[i].buffer_length= sizeof (dbl_data); + break; + + case MYSQL_TYPE_NEWDECIMAL: + rs_bind[i].buffer= (char *) dec_data[i]; + rs_bind[i].buffer_length= WL4435_STRING_SIZE; + rs_bind[i].length= &str_length; + break; + + default: + fprintf(stderr, "ERROR: unexpected type: %d.\n", fields[i].type); + exit(1); + } + } + + rc= mysql_stmt_bind_result(stmt, rs_bind); + check_execute(stmt, rc); + + mct_log("Data:\n"); + + while (1) + { + int rc= mysql_stmt_fetch(stmt); + + if (rc == 1 || rc == MYSQL_NO_DATA) + break; + + mct_log(" "); + + for (i = 0; i < num_fields; ++i) + { + switch (rs_bind[i].buffer_type) + { + case MYSQL_TYPE_LONG: + mct_log(" int: %ld;", + (long) *((int *) rs_bind[i].buffer)); + break; + + case MYSQL_TYPE_STRING: + mct_log(" str: '%s';", + (char *) rs_bind[i].buffer); + break; + + case MYSQL_TYPE_DOUBLE: + mct_log(" dbl: %lf;", + (double) *((double *) rs_bind[i].buffer)); + break; + + case MYSQL_TYPE_NEWDECIMAL: + mct_log(" dec: '%s';", + (char *) rs_bind[i].buffer); + break; + + default: + printf(" unexpected type (%d)\n", + rs_bind[i].buffer_type); + } + } + mct_log("\n"); + } + + mct_log("EOF\n"); + + rc= mysql_stmt_next_result(stmt); + mct_log("mysql_stmt_next_result(): %d; field_count: %d\n", + (int) rc, (int) mysql->field_count); + + free(rs_bind); + mysql_free_result(rs_metadata); + + if (rc > 0) + { + printf("Error: %s (errno: %d)\n", + mysql_stmt_error(stmt), mysql_stmt_errno(stmt)); + DIE(rc > 0); + } + + if (rc) + break; + + if (!mysql->field_count) + { + /* This is the last OK-packet. No more resultsets. */ + break; + } + } + + } + + mysql_stmt_close(stmt); + + mct_close_log(); + + rc= mysql_commit(mysql); + myquery(rc); + + /* i18n part of test case. */ + + { + const char *str_koi8r= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5"; + const char *str_cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3"; + char o1_buffer[255]; + ulong o1_length; + char o2_buffer[255]; + ulong o2_length; + + MYSQL_BIND rs_bind[2]; + + strmov(query, "CALL p2(?, ?, ?)"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + /* Init PS-parameters. */ + + bzero((char *) ps_params, sizeof (ps_params)); + + ps_params[0].buffer_type= MYSQL_TYPE_STRING; + ps_params[0].buffer= (char *) str_koi8r; + ps_params[0].buffer_length= strlen(str_koi8r); + + ps_params[1].buffer_type= MYSQL_TYPE_STRING; + ps_params[1].buffer= o1_buffer; + ps_params[1].buffer_length= 0; + + ps_params[2].buffer_type= MYSQL_TYPE_STRING; + ps_params[2].buffer= o2_buffer; + ps_params[2].buffer_length= 0; + + /* Bind parameters. */ + + rc= mysql_stmt_bind_param(stmt, ps_params); + check_execute(stmt, rc); + + /* Prevent converting to character_set_results. */ + + rc= mysql_query(mysql, "SET NAMES binary"); + myquery(rc); + + /* Execute statement. */ + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + /* Bind result. */ + + bzero(rs_bind, sizeof (rs_bind)); + + rs_bind[0].buffer_type= MYSQL_TYPE_STRING; + rs_bind[0].buffer= o1_buffer; + rs_bind[0].buffer_length= sizeof (o1_buffer); + rs_bind[0].length= &o1_length; + + rs_bind[1].buffer_type= MYSQL_TYPE_BLOB; + rs_bind[1].buffer= o2_buffer; + rs_bind[1].buffer_length= sizeof (o2_buffer); + rs_bind[1].length= &o2_length; + + rc= mysql_stmt_bind_result(stmt, rs_bind); + check_execute(stmt, rc); + + /* Fetch result. */ + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + /* Check result. */ + + DIE_UNLESS(o1_length == strlen(str_cp1251)); + DIE_UNLESS(o2_length == strlen(str_koi8r)); + DIE_UNLESS(!memcmp(o1_buffer, str_cp1251, o1_length)); + DIE_UNLESS(!memcmp(o2_buffer, str_koi8r, o2_length)); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_next_result(stmt); + DIE_UNLESS(rc == 0 && mysql->field_count == 0); + + mysql_stmt_close(stmt); + + rc= mysql_commit(mysql); + myquery(rc); + } +} + +static void test_wl4435_2() +{ + MYSQL_STMT *stmt; + int i; + int rc; + char query[MAX_TEST_QUERY_LENGTH]; + + myheader("test_wl4435_2"); + mct_start_logging("test_wl4435_2"); + + /* + Do a few iterations so that we catch any problem with incorrect + handling/flushing prepared statement results. + */ + + for (i= 0; i < 10; ++i) + { + /* + Prepare a procedure. That can be moved out of the loop, but it was + left in the loop for the sake of having as many statements as + possible. + */ + + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(mysql, + "CREATE PROCEDURE p1()" + "BEGIN " + " SELECT 1; " + " SELECT 2, 3 UNION SELECT 4, 5; " + " SELECT 6, 7, 8; " + "END"); + myquery(rc); + + /* Invoke a procedure, that returns several result sets. */ + + strmov(query, "CALL p1()"); + stmt= mysql_simple_prepare(mysql, query); + check_stmt(stmt); + + /* Execute! */ + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + /* Flush all the results. */ + + mysql_stmt_close(stmt); + + /* Clean up. */ + rc= mysql_commit(mysql); + myquery(rc); + + rc= mysql_query(mysql, "DROP PROCEDURE p1"); + myquery(rc); + } +} + + +#define WL4435_TEST(sql_type, sql_value, \ + c_api_in_type, c_api_out_type, \ + c_type, c_type_ext, \ + printf_args, assert_condition) \ +\ + do { \ + int rc; \ + MYSQL_STMT *ps; \ + MYSQL_BIND psp; \ + MYSQL_RES *rs_metadata; \ + MYSQL_FIELD *fields; \ + c_type pspv c_type_ext; \ + my_bool psp_null; \ + \ + bzero(&pspv, sizeof (pspv)); \ + \ + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1"); \ + myquery(rc); \ + \ + rc= mysql_query(mysql, \ + "CREATE PROCEDURE p1(OUT v " sql_type ") SET v = " sql_value ";"); \ + myquery(rc); \ + \ + ps = mysql_simple_prepare(mysql, "CALL p1(?)"); \ + check_stmt(ps); \ + \ + bzero(&psp, sizeof (psp)); \ + psp.buffer_type= c_api_in_type; \ + psp.is_null= &psp_null; \ + psp.buffer= (char *) &pspv; \ + psp.buffer_length= sizeof (psp); \ + \ + rc= mysql_stmt_bind_param(ps, &psp); \ + check_execute(ps, rc); \ + \ + rc= mysql_stmt_execute(ps); \ + check_execute(ps, rc); \ + \ + DIE_UNLESS(mysql->server_status & SERVER_PS_OUT_PARAMS); \ + DIE_UNLESS(mysql_stmt_field_count(ps) == 1); \ + \ + rs_metadata= mysql_stmt_result_metadata(ps); \ + fields= mysql_fetch_fields(rs_metadata); \ + \ + rc= mysql_stmt_bind_result(ps, &psp); \ + check_execute(ps, rc); \ + \ + rc= mysql_stmt_fetch(ps); \ + DIE_UNLESS(rc == 0); \ + \ + DIE_UNLESS(fields[0].type == c_api_out_type); \ + printf printf_args; \ + printf("; in type: %d; out type: %d\n", \ + (int) c_api_in_type, (int) c_api_out_type); \ + \ + rc= mysql_stmt_fetch(ps); \ + DIE_UNLESS(rc == MYSQL_NO_DATA); \ + \ + rc= mysql_stmt_next_result(ps); \ + DIE_UNLESS(rc == 0); \ + \ + mysql_stmt_free_result(ps); \ + mysql_stmt_close(ps); \ + \ + DIE_UNLESS(assert_condition); \ + \ + } while (0) + +static void test_wl4435_3() +{ + char tmp[255]; + + puts(""); + + // The following types are not supported: + // - ENUM + // - SET + // + // The following types are supported but can not be used for + // OUT-parameters: + // - MEDIUMINT; + // - BIT(..); + // + // The problem is that those types are not supported for IN-parameters, + // and OUT-parameters should be bound as IN-parameters before execution. + // + // The following types should not be used: + // - MYSQL_TYPE_YEAR (use MYSQL_TYPE_SHORT instead); + // - MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB + // (use MYSQL_TYPE_BLOB instead); + + WL4435_TEST("TINYINT", "127", + MYSQL_TYPE_TINY, MYSQL_TYPE_TINY, + char, , + (" - TINYINT / char / MYSQL_TYPE_TINY:\t\t\t %d", (int) pspv), + pspv == 127); + + WL4435_TEST("SMALLINT", "32767", + MYSQL_TYPE_SHORT, MYSQL_TYPE_SHORT, + short, , + (" - SMALLINT / short / MYSQL_TYPE_SHORT:\t\t %d", (int) pspv), + pspv == 32767); + + WL4435_TEST("INT", "2147483647", + MYSQL_TYPE_LONG, MYSQL_TYPE_LONG, + int, , + (" - INT / int / MYSQL_TYPE_LONG:\t\t\t %d", pspv), + pspv == 2147483647l); + + WL4435_TEST("BIGINT", "9223372036854775807", + MYSQL_TYPE_LONGLONG, MYSQL_TYPE_LONGLONG, + long long, , + (" - BIGINT / long long / MYSQL_TYPE_LONGLONG:\t\t %lld", pspv), + pspv == 9223372036854775807ll); + + WL4435_TEST("TIMESTAMP", "'2007-11-18 15:01:02'", + MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_TIMESTAMP, + MYSQL_TIME, , + (" - TIMESTAMP / MYSQL_TIME / MYSQL_TYPE_TIMESTAMP:\t " + "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", + (int) pspv.year, (int) pspv.month, (int) pspv.day, + (int) pspv.hour, (int) pspv.minute, (int) pspv.second), + pspv.year == 2007 && pspv.month == 11 && pspv.day == 18 && + pspv.hour == 15 && pspv.minute == 1 && pspv.second == 2); + + WL4435_TEST("DATETIME", "'1234-11-12 12:34:59'", + MYSQL_TYPE_DATETIME, MYSQL_TYPE_DATETIME, + MYSQL_TIME, , + (" - DATETIME / MYSQL_TIME / MYSQL_TYPE_DATETIME:\t " + "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", + (int) pspv.year, (int) pspv.month, (int) pspv.day, + (int) pspv.hour, (int) pspv.minute, (int) pspv.second), + pspv.year == 1234 && pspv.month == 11 && pspv.day == 12 && + pspv.hour == 12 && pspv.minute == 34 && pspv.second == 59); + + WL4435_TEST("TIME", "'123:45:01'", + MYSQL_TYPE_TIME, MYSQL_TYPE_TIME, + MYSQL_TIME, , + (" - TIME / MYSQL_TIME / MYSQL_TYPE_TIME:\t\t " + "%.3d:%.2d:%.2d", + (int) pspv.hour, (int) pspv.minute, (int) pspv.second), + pspv.hour == 123 && pspv.minute == 45 && pspv.second == 1); + + WL4435_TEST("DATE", "'1234-11-12'", + MYSQL_TYPE_DATE, MYSQL_TYPE_DATE, + MYSQL_TIME, , + (" - DATE / MYSQL_TIME / MYSQL_TYPE_DATE:\t\t " + "%.4d-%.2d-%.2d", + (int) pspv.year, (int) pspv.month, (int) pspv.day), + pspv.year == 1234 && pspv.month == 11 && pspv.day == 12); + + WL4435_TEST("YEAR", "'2010'", + MYSQL_TYPE_SHORT, MYSQL_TYPE_YEAR, + short, , + (" - YEAR / short / MYSQL_TYPE_SHORT:\t\t\t %.4d", (int) pspv), + pspv == 2010); + + WL4435_TEST("FLOAT(7, 4)", "123.4567", + MYSQL_TYPE_FLOAT, MYSQL_TYPE_FLOAT, + float, , + (" - FLOAT / float / MYSQL_TYPE_FLOAT:\t\t\t %g", (double) pspv), + pspv - 123.4567 < 0.0001); + + WL4435_TEST("DOUBLE(8, 5)", "123.45678", + MYSQL_TYPE_DOUBLE, MYSQL_TYPE_DOUBLE, + double, , + (" - DOUBLE / double / MYSQL_TYPE_DOUBLE:\t\t %g", (double) pspv), + pspv - 123.45678 < 0.00001); + + WL4435_TEST("DECIMAL(9, 6)", "123.456789", + MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_NEWDECIMAL, + char, [255], + (" - DECIMAL / char[] / MYSQL_TYPE_NEWDECIMAL:\t\t '%s'", (char *) pspv), + !strcmp(pspv, "123.456789")); + + WL4435_TEST("CHAR(32)", "REPEAT('C', 16)", + MYSQL_TYPE_STRING, MYSQL_TYPE_STRING, + char, [255], + (" - CHAR(32) / char[] / MYSQL_TYPE_STRING:\t\t '%s'", (char *) pspv), + !strcmp(pspv, "CCCCCCCCCCCCCCCC")); + + WL4435_TEST("VARCHAR(32)", "REPEAT('V', 16)", + MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING, + char, [255], + (" - VARCHAR(32) / char[] / MYSQL_TYPE_VAR_STRING:\t '%s'", (char *) pspv), + !strcmp(pspv, "VVVVVVVVVVVVVVVV")); + + WL4435_TEST("TINYTEXT", "REPEAT('t', 16)", + MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - TINYTEXT / char[] / MYSQL_TYPE_TINY_BLOB:\t\t '%s'", (char *) pspv), + !strcmp(pspv, "tttttttttttttttt")); + + WL4435_TEST("TEXT", "REPEAT('t', 16)", + MYSQL_TYPE_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - TEXT / char[] / MYSQL_TYPE_BLOB:\t\t\t '%s'", (char *) pspv), + !strcmp(pspv, "tttttttttttttttt")); + + WL4435_TEST("MEDIUMTEXT", "REPEAT('t', 16)", + MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - MEDIUMTEXT / char[] / MYSQL_TYPE_MEDIUM_BLOB:\t '%s'", (char *) pspv), + !strcmp(pspv, "tttttttttttttttt")); + + WL4435_TEST("LONGTEXT", "REPEAT('t', 16)", + MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - LONGTEXT / char[] / MYSQL_TYPE_LONG_BLOB:\t\t '%s'", (char *) pspv), + !strcmp(pspv, "tttttttttttttttt")); + + WL4435_TEST("BINARY(32)", "REPEAT('\1', 16)", + MYSQL_TYPE_STRING, MYSQL_TYPE_STRING, + char, [255], + (" - BINARY(32) / char[] / MYSQL_TYPE_STRING:\t\t '%s'", (char *) pspv), + memset(tmp, 1, 16) && !memcmp(tmp, pspv, 16)); + + WL4435_TEST("VARBINARY(32)", "REPEAT('\1', 16)", + MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VAR_STRING, + char, [255], + (" - VARBINARY(32) / char[] / MYSQL_TYPE_VAR_STRING:\t '%s'", (char *) pspv), + memset(tmp, 1, 16) && !memcmp(tmp, pspv, 16)); + + WL4435_TEST("TINYBLOB", "REPEAT('\2', 16)", + MYSQL_TYPE_TINY_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - TINYBLOB / char[] / MYSQL_TYPE_TINY_BLOB:\t\t '%s'", (char *) pspv), + memset(tmp, 2, 16) && !memcmp(tmp, pspv, 16)); + + WL4435_TEST("BLOB", "REPEAT('\2', 16)", + MYSQL_TYPE_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - BLOB / char[] / MYSQL_TYPE_BLOB:\t\t\t '%s'", (char *) pspv), + memset(tmp, 2, 16) && !memcmp(tmp, pspv, 16)); + + WL4435_TEST("MEDIUMBLOB", "REPEAT('\2', 16)", + MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - MEDIUMBLOB / char[] / MYSQL_TYPE_MEDIUM_BLOB:\t '%s'", (char *) pspv), + memset(tmp, 2, 16) && !memcmp(tmp, pspv, 16)); + + WL4435_TEST("LONGBLOB", "REPEAT('\2', 16)", + MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_BLOB, + char, [255], + (" - LONGBLOB / char[] / MYSQL_TYPE_LONG_BLOB:\t\t '%s'", (char *) pspv), + memset(tmp, 2, 16) && !memcmp(tmp, pspv, 16)); +} + /* Test simple prepare field results */ @@ -594,7 +1407,7 @@ static void test_prepare() /* now, execute the prepared statement to insert 10 records.. */ for (tiny_data= 0; tiny_data < 100; tiny_data++) { - length[1]= my_sprintf(str_data, (str_data, "MySQL%d", int_data)); + length[1]= sprintf(str_data, "MySQL%d", int_data); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); int_data += 25; @@ -633,7 +1446,7 @@ static void test_prepare() /* now, execute the prepared statement to insert 10 records.. */ for (o_tiny_data= 0; o_tiny_data < 100; o_tiny_data++) { - len= my_sprintf(data, (data, "MySQL%d", o_int_data)); + len= sprintf(data, "MySQL%d", o_int_data); rc= mysql_stmt_fetch(stmt); check_execute(stmt, rc); @@ -1496,6 +2309,7 @@ static void test_ps_query_cache() if (!opt_silent) fprintf(stdout, "OK"); + break; } strmov(query, "select id1, value1 from t1 where id1= ? or " @@ -2033,7 +2847,7 @@ static void test_simple_update() my_bind[0].buffer= szData; /* string data */ my_bind[0].buffer_length= sizeof(szData); my_bind[0].length= &length[0]; - length[0]= my_sprintf(szData, (szData, "updated-data")); + length[0]= sprintf(szData, "updated-data"); my_bind[1].buffer= (void *) &nData; my_bind[1].buffer_type= MYSQL_TYPE_LONG; @@ -2287,7 +3101,7 @@ static void test_long_data_str1() rc= mysql_stmt_bind_param(stmt, my_bind); check_execute(stmt, rc); - length= my_sprintf(data, (data, "MySQL AB")); + length= sprintf(data, "MySQL AB"); /* supply data in pieces */ for (i= 0; i < 3; i++) @@ -2602,7 +3416,7 @@ static void test_update() my_bind[0].buffer= szData; my_bind[0].buffer_length= sizeof(szData); my_bind[0].length= &length[0]; - length[0]= my_sprintf(szData, (szData, "inserted-data")); + length[0]= sprintf(szData, "inserted-data"); my_bind[1].buffer= (void *)&nData; my_bind[1].buffer_type= MYSQL_TYPE_LONG; @@ -2631,7 +3445,7 @@ static void test_update() my_bind[0].buffer= szData; my_bind[0].buffer_length= sizeof(szData); my_bind[0].length= &length[0]; - length[0]= my_sprintf(szData, (szData, "updated-data")); + length[0]= sprintf(szData, "updated-data"); my_bind[1].buffer= (void *)&nData; my_bind[1].buffer_type= MYSQL_TYPE_LONG; @@ -3200,7 +4014,7 @@ static void bind_fetch(int row_count) /* CHAR */ { char buff[20]; - long len= my_sprintf(buff, (buff, "%d", rc)); + long len= sprintf(buff, "%d", rc); DIE_UNLESS(strcmp(s_data, buff) == 0); DIE_UNLESS(length[6] == (ulong) len); } @@ -3793,7 +4607,7 @@ static void test_insert() /* now, execute the prepared statement to insert 10 records.. */ for (tiny_data= 0; tiny_data < 3; tiny_data++) { - length= my_sprintf(str_data, (str_data, "MySQL%d", tiny_data)); + length= sprintf(str_data, "MySQL%d", tiny_data); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); } @@ -4031,7 +4845,7 @@ static void test_stmt_close() } -/* Test simple set-variable prepare */ +/* Test simple set variable prepare */ static void test_set_variable() { @@ -4133,215 +4947,6 @@ static void test_set_variable() mysql_stmt_close(stmt1); } -#if NOT_USED - -/* Insert meta info .. */ - -static void test_insert_meta() -{ - MYSQL_STMT *stmt; - int rc; - MYSQL_RES *result; - MYSQL_FIELD *field; - - myheader("test_insert_meta"); - - rc= mysql_autocommit(mysql, TRUE); - myquery(rc); - - rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prep_insert"); - myquery(rc); - - rc= mysql_query(mysql, "CREATE TABLE test_prep_insert(col1 tinyint, \ - col2 varchar(50), col3 varchar(30))"); - myquery(rc); - - strmov(query, "INSERT INTO test_prep_insert VALUES(10, 'venu1', 'test')"); - stmt= mysql_simple_prepare(mysql, query); - check_stmt(stmt); - - verify_param_count(stmt, 0); - - result= mysql_param_result(stmt); - mytest_r(result); - - mysql_stmt_close(stmt); - - strmov(query, "INSERT INTO test_prep_insert VALUES(?, 'venu', ?)"); - stmt= mysql_simple_prepare(mysql, query); - check_stmt(stmt); - - verify_param_count(stmt, 2); - - result= mysql_param_result(stmt); - mytest(result); - - my_print_result_metadata(result); - - mysql_field_seek(result, 0); - field= mysql_fetch_field(result); - mytest(field); - if (!opt_silent) - fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", field->name, "col1"); - DIE_UNLESS(strcmp(field->name, "col1") == 0); - - field= mysql_fetch_field(result); - mytest(field); - if (!opt_silent) - fprintf(stdout, "\n obtained: `%s` (expected: `%s`)", field->name, "col3"); - DIE_UNLESS(strcmp(field->name, "col3") == 0); - - field= mysql_fetch_field(result); - mytest_r(field); - - mysql_free_result(result); - mysql_stmt_close(stmt); -} - - -/* Update meta info .. */ - -static void test_update_meta() -{ - MYSQL_STMT *stmt; - int rc; - MYSQL_RES *result; - MYSQL_FIELD *field; - - myheader("test_update_meta"); - - rc= mysql_autocommit(mysql, TRUE); - myquery(rc); - - rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prep_update"); - myquery(rc); - - rc= mysql_query(mysql, "CREATE TABLE test_prep_update(col1 tinyint, \ - col2 varchar(50), col3 varchar(30))"); - myquery(rc); - - strmov(query, "UPDATE test_prep_update SET col1=10, col2='venu1' WHERE col3='test'"); - stmt= mysql_simple_prepare(mysql, query); - check_stmt(stmt); - - verify_param_count(stmt, 0); - - result= mysql_param_result(stmt); - mytest_r(result); - - mysql_stmt_close(stmt); - - strmov(query, "UPDATE test_prep_update SET col1=?, col2='venu' WHERE col3=?"); - stmt= mysql_simple_prepare(mysql, query); - check_stmt(stmt); - - verify_param_count(stmt, 2); - - result= mysql_param_result(stmt); - mytest(result); - - my_print_result_metadata(result); - - mysql_field_seek(result, 0); - field= mysql_fetch_field(result); - mytest(field); - if (!opt_silent) - { - fprintf(stdout, "\n col obtained: `%s` (expected: `%s`)", field->name, "col1"); - fprintf(stdout, "\n tab obtained: `%s` (expected: `%s`)", field->table, "test_prep_update"); - } - DIE_UNLESS(strcmp(field->name, "col1") == 0); - DIE_UNLESS(strcmp(field->table, "test_prep_update") == 0); - - field= mysql_fetch_field(result); - mytest(field); - if (!opt_silent) - { - fprintf(stdout, "\n col obtained: `%s` (expected: `%s`)", field->name, "col3"); - fprintf(stdout, "\n tab obtained: `%s` (expected: `%s`)", field->table, "test_prep_update"); - } - DIE_UNLESS(strcmp(field->name, "col3") == 0); - DIE_UNLESS(strcmp(field->table, "test_prep_update") == 0); - - field= mysql_fetch_field(result); - mytest_r(field); - - mysql_free_result(result); - mysql_stmt_close(stmt); -} - - -/* Select meta info .. */ - -static void test_select_meta() -{ - MYSQL_STMT *stmt; - int rc; - MYSQL_RES *result; - MYSQL_FIELD *field; - - myheader("test_select_meta"); - - rc= mysql_autocommit(mysql, TRUE); - myquery(rc); - - rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_prep_select"); - myquery(rc); - - rc= mysql_query(mysql, "CREATE TABLE test_prep_select(col1 tinyint, \ - col2 varchar(50), col3 varchar(30))"); - myquery(rc); - - strmov(query, "SELECT * FROM test_prep_select WHERE col1=10"); - stmt= mysql_simple_prepare(mysql, query); - check_stmt(stmt); - - verify_param_count(stmt, 0); - - result= mysql_param_result(stmt); - mytest_r(result); - - strmov(query, "SELECT col1, col3 from test_prep_select WHERE col1=? AND col3='test' AND col2= ?"); - stmt= mysql_simple_prepare(mysql, query); - check_stmt(stmt); - - verify_param_count(stmt, 2); - - result= mysql_param_result(stmt); - mytest(result); - - my_print_result_metadata(result); - - mysql_field_seek(result, 0); - field= mysql_fetch_field(result); - mytest(field); - if (!opt_silent) - { - fprintf(stdout, "\n col obtained: `%s` (expected: `%s`)", field->name, "col1"); - fprintf(stdout, "\n tab obtained: `%s` (expected: `%s`)", field->table, "test_prep_select"); - } - DIE_UNLESS(strcmp(field->name, "col1") == 0); - DIE_UNLESS(strcmp(field->table, "test_prep_select") == 0); - - field= mysql_fetch_field(result); - mytest(field); - if (!opt_silent) - { - fprintf(stdout, "\n col obtained: `%s` (expected: `%s`)", field->name, "col2"); - fprintf(stdout, "\n tab obtained: `%s` (expected: `%s`)", field->table, "test_prep_select"); - } - DIE_UNLESS(strcmp(field->name, "col2") == 0); - DIE_UNLESS(strcmp(field->table, "test_prep_select") == 0); - - field= mysql_fetch_field(result); - mytest_r(field); - - mysql_free_result(result); - mysql_stmt_close(stmt); -} -#endif - - /* Test FUNCTION field info / DATE_FORMAT() table_name . */ static void test_func_fields() @@ -6716,26 +7321,26 @@ static void test_explain_bug() verify_prepare_field(result, 0, "Field", "COLUMN_NAME", mysql_get_server_version(mysql) <= 50000 ? MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, - 0, 0, "", 64, 0); + 0, 0, "information_schema", 64, 0); verify_prepare_field(result, 1, "Type", "COLUMN_TYPE", MYSQL_TYPE_BLOB, - 0, 0, "", 0, 0); + 0, 0, "information_schema", 0, 0); verify_prepare_field(result, 2, "Null", "IS_NULLABLE", mysql_get_server_version(mysql) <= 50000 ? MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, - 0, 0, "", 3, 0); + 0, 0, "information_schema", 3, 0); verify_prepare_field(result, 3, "Key", "COLUMN_KEY", mysql_get_server_version(mysql) <= 50000 ? MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, - 0, 0, "", 3, 0); + 0, 0, "information_schema", 3, 0); if ( mysql_get_server_version(mysql) >= 50027 ) { /* The patch for bug#23037 changes column type of DEAULT to blob */ verify_prepare_field(result, 4, "Default", "COLUMN_DEFAULT", - MYSQL_TYPE_BLOB, 0, 0, "", 0, 0); + MYSQL_TYPE_BLOB, 0, 0, "information_schema", 0, 0); } else { @@ -6744,14 +7349,14 @@ static void test_explain_bug() MYSQL_TYPE_BLOB : mysql_get_server_version(mysql) <= 50000 ? MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, - 0, 0, "", + 0, 0, "information_schema", mysql_get_server_version(mysql) >= 50027 ? 0 :64, 0); } verify_prepare_field(result, 5, "Extra", "EXTRA", mysql_get_server_version(mysql) <= 50000 ? MYSQL_TYPE_STRING : MYSQL_TYPE_VAR_STRING, - 0, 0, "", 27, 0); + 0, 0, "information_schema", 27, 0); mysql_free_result(result); mysql_stmt_close(stmt); @@ -11445,7 +12050,7 @@ static void test_datetime_ranges() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - DIE_UNLESS(mysql_warning_count(mysql) == 6); + my_process_warnings(mysql, 6); verify_col_data("t1", "year", "0000-00-00 00:00:00"); verify_col_data("t1", "month", "0000-00-00 00:00:00"); @@ -11476,7 +12081,7 @@ static void test_datetime_ranges() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - DIE_UNLESS(mysql_warning_count(mysql) == 3); + my_process_warnings(mysql, 3); verify_col_data("t1", "year", "0000-00-00 00:00:00"); verify_col_data("t1", "month", "0000-00-00 00:00:00"); @@ -11515,7 +12120,7 @@ static void test_datetime_ranges() rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); - DIE_UNLESS(mysql_warning_count(mysql) == 2); + my_process_warnings(mysql, 2); verify_col_data("t1", "day_ovfl", "838:59:59"); verify_col_data("t1", "day", "828:30:30"); @@ -11751,7 +12356,10 @@ static void test_truncation() ")"; rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); myquery(rc); - stmt_text= "insert into t1 VALUES (" + + { + const char insert_text[]= + "insert into t1 VALUES (" "-10, " /* i8 */ "200, " /* ui8 */ "32000, " /* i16 */ @@ -11767,8 +12375,9 @@ static void test_truncation() "'12345.67 ', " /* tx_1 */ "'12345.67abc'" /* ch_2 */ ")"; - rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); - myquery(rc); + rc= mysql_real_query(mysql, insert_text, strlen(insert_text)); + myquery(rc); + } stmt_text= "select i8 c1, i8 c2, ui8 c3, i16_1 c4, ui16 c5, " " i16 c6, ui16 c7, i32 c8, i32_1 c9, i32_1 c10, " @@ -12417,6 +13026,49 @@ static void test_bug8880() mysql_stmt_close(*stmt); } +/* + Test executing a query with prepared statements while query cache is active +*/ + +static void test_open_cursor_prepared_statement_query_cache() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_RES *result; + + myheader("test_open_cursor_prepared_statement_query_cache"); + if (! is_query_cache_available()) + { + fprintf(stdout, "Skipping test_open_cursor_prepared_statement_query_cache: Query cache not available.\n"); + return; + } + + rc= mysql_query(mysql, "set global query_cache_size=1000000"); + myquery(rc); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (a int not null primary key, b int)"); + rc= mysql_query(mysql, "insert into t1 values (1,1)"); + myquery(rc); /* one check is enough */ + + /* Store query in query cache */ + rc= mysql_query(mysql, "SELECT * FROM t1"); + myquery(rc); + result= mysql_store_result(mysql); + mytest(result); + (void) my_process_result_set(result); + mysql_free_result(result); + + /* Test using a cursor */ + stmt= open_cursor("select a from t1"); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "set global query_cache_size=1000000"); + myquery(rc); +} + static void test_bug9159() { @@ -13435,9 +14087,8 @@ static void test_bug12001() /* Create connection that supports multi statements */ if (!mysql_real_connect(mysql_local, opt_host, opt_user, - opt_password, current_db, opt_port, - opt_unix_socket, CLIENT_MULTI_STATEMENTS | - CLIENT_MULTI_RESULTS)) + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_MULTI_STATEMENTS)) { fprintf(stdout, "\n mysql_real_connect() failed"); exit(1); @@ -14001,8 +14652,11 @@ static void test_bug13488() check_execute(stmt1, rc); if (!opt_silent) - printf("data is: %s", (f1 == 1 && f2 == 1 && f3 == 2)?"OK": - "wrong"); + { + printf("data: f1: %d; f2: %d; f3: %d\n", f1, f2, f3); + printf("data is: %s\n", + (f1 == 1 && f2 == 1 && f3 == 2) ? "OK" : "wrong"); + } DIE_UNLESS(f1 == 1 && f2 == 1 && f3 == 2); rc= mysql_query(mysql, "drop table t1, t2"); myquery(rc); @@ -14805,7 +15459,7 @@ static void test_bug15752() if (! mysql_real_connect(&mysql_local, opt_host, opt_user, opt_password, current_db, opt_port, opt_unix_socket, - CLIENT_MULTI_STATEMENTS|CLIENT_MULTI_RESULTS)) + CLIENT_MULTI_STATEMENTS)) { printf("Unable connect to MySQL server: %s\n", mysql_error(&mysql_local)); DIE_UNLESS(0); @@ -16093,9 +16747,9 @@ static void test_bug20023() SQL_BIG_SELECTS will be 1. ***********************************************************************/ - /* Set MAX_JOIN_SIZE to the default value (-1). */ + /* Set MAX_JOIN_SIZE to the default value (2^64-1). */ - DIE_IF(mysql_query(&con, "SET @@global.max_join_size = 18446744073709551615")); + DIE_IF(mysql_query(&con, "SET @@global.max_join_size = cast(-1 as unsigned int)")); DIE_IF(mysql_query(&con, "SET @@session.max_join_size = default")); /* Issue COM_CHANGE_USER. */ @@ -16126,7 +16780,7 @@ static void test_bug20023() DIE_IF(mysql_query(&con, query_buffer)); - DIE_IF(mysql_query(&con, "SET @@global.max_join_size = 18446744073709551615")); + DIE_IF(mysql_query(&con, "SET @@global.max_join_size = cast(-1 as unsigned int)")); DIE_IF(mysql_query(&con, "SET @@session.max_join_size = default")); /* Issue COM_CHANGE_USER. */ @@ -16249,13 +16903,14 @@ static void test_bug31418() */ #define LARGE_BUFFER_SIZE 2048 +#define OLD_USERNAME_CHAR_LENGTH 16 static void test_bug31669() { int rc; static char buff[LARGE_BUFFER_SIZE+1]; #ifndef EMBEDDED_LIBRARY - static char user[USERNAME_CHAR_LENGTH+1]; + static char user[OLD_USERNAME_CHAR_LENGTH+1]; static char db[NAME_CHAR_LEN+1]; static char query[LARGE_BUFFER_SIZE*2]; #endif @@ -16292,7 +16947,7 @@ static void test_bug31669() myquery(rc); memset(user, 'b', sizeof(user)); - user[USERNAME_CHAR_LENGTH]= 0; + user[OLD_USERNAME_CHAR_LENGTH]= 0; memset(buff, 'c', sizeof(buff)); buff[LARGE_BUFFER_SIZE]= 0; strxmov(query, "GRANT ALL PRIVILEGES ON *.* TO '", user, "'@'%' IDENTIFIED BY " @@ -16311,11 +16966,11 @@ static void test_bug31669() rc= mysql_change_user(conn, user, buff, db); DIE_UNLESS(!rc); - user[USERNAME_CHAR_LENGTH-1]= 'a'; + user[OLD_USERNAME_CHAR_LENGTH-1]= 'a'; rc= mysql_change_user(conn, user, buff, db); DIE_UNLESS(rc); - user[USERNAME_CHAR_LENGTH-1]= 'b'; + user[OLD_USERNAME_CHAR_LENGTH-1]= 'b'; buff[LARGE_BUFFER_SIZE-1]= 'd'; rc= mysql_change_user(conn, user, buff, db); DIE_UNLESS(rc); @@ -16431,6 +17086,7 @@ static void test_bug28386() DBUG_VOID_RETURN; } + static void test_wl4166_1() { MYSQL_STMT *stmt; @@ -16509,7 +17165,7 @@ static void test_wl4166_1() /* now, execute the prepared statement to insert 10 records.. */ for (tiny_data= 0; tiny_data < 10; tiny_data++) { - length[1]= my_sprintf(str_data, (str_data, "MySQL%d", int_data)); + length[1]= sprintf(str_data, "MySQL%d", int_data); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); int_data += 25; @@ -16532,7 +17188,7 @@ static void test_wl4166_1() for (tiny_data= 50; tiny_data < 60; tiny_data++) { - length[1]= my_sprintf(str_data, (str_data, "MySQL%d", int_data)); + length[1]= sprintf(str_data, "MySQL%d", int_data); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); int_data += 25; @@ -16642,10 +17298,266 @@ static void test_wl4166_2() } + +/** + Test how warnings generated during assignment of parameters + are (currently not) preserve in case of reprepare. +*/ + +static void test_wl4166_3() +{ + int rc; + MYSQL_STMT *stmt; + MYSQL_BIND my_bind[1]; + MYSQL_TIME tm[1]; + + myheader("test_wl4166_3"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + + rc= mysql_query(mysql, "create table t1 (year datetime)"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "insert into t1 (year) values (?)"); + check_stmt(stmt); + verify_param_count(stmt, 1); + + bzero((char*) my_bind, sizeof(my_bind)); + my_bind[0].buffer_type= MYSQL_TYPE_DATETIME; + my_bind[0].buffer= &tm[0]; + + rc= mysql_stmt_bind_param(stmt, my_bind); + check_execute(stmt, rc); + + tm[0].year= 10000; + tm[0].month= 1; tm[0].day= 1; + tm[0].hour= 1; tm[0].minute= 1; tm[0].second= 1; + tm[0].second_part= 0; tm[0].neg= 0; + + /* Cause a statement reprepare */ + rc= mysql_query(mysql, "alter table t1 add column c int"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + /* + Sic: only one warning, instead of two. The warning + about data truncation when assigning a parameter is lost. + This is a bug. + */ + my_process_warnings(mysql, 1); + + verify_col_data("t1", "year", "0000-00-00 00:00:00"); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/** + Test that long data parameters, as well as parameters + that were originally in a different character set, are + preserved in case of reprepare. +*/ + +static void test_wl4166_4() +{ + MYSQL_STMT *stmt; + int rc; + const char *stmt_text; + MYSQL_BIND bind_array[2]; + + /* Represented as numbers to keep UTF8 tools from clobbering them. */ + const char *koi8= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5"; + const char *cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3"; + char buf1[16], buf2[16]; + ulong buf1_len, buf2_len; + + myheader("test_wl4166_4"); + + rc= mysql_query(mysql, "drop table if exists t1"); + myquery(rc); + + /* + Create table with binary columns, set session character set to cp1251, + client character set to koi8, and make sure that there is conversion + on insert and no conversion on select + */ + rc= mysql_query(mysql, + "create table t1 (c1 varbinary(255), c2 varbinary(255))"); + myquery(rc); + rc= mysql_query(mysql, "set character_set_client=koi8r, " + "character_set_connection=cp1251, " + "character_set_results=koi8r"); + myquery(rc); + + bzero((char*) bind_array, sizeof(bind_array)); + + bind_array[0].buffer_type= MYSQL_TYPE_STRING; + + bind_array[1].buffer_type= MYSQL_TYPE_STRING; + bind_array[1].buffer= (void *) koi8; + bind_array[1].buffer_length= strlen(koi8); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + stmt_text= "insert into t1 (c1, c2) values (?, ?)"; + + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + mysql_stmt_bind_param(stmt, bind_array); + + mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8)); + + /* Cause a reprepare at statement execute */ + rc= mysql_query(mysql, "alter table t1 add column d int"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + stmt_text= "select c1, c2 from t1"; + + /* c1 and c2 are binary so no conversion will be done on select */ + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bind_array[0].buffer= buf1; + bind_array[0].buffer_length= sizeof(buf1); + bind_array[0].length= &buf1_len; + + bind_array[1].buffer= buf2; + bind_array[1].buffer_length= sizeof(buf2); + bind_array[1].length= &buf2_len; + + mysql_stmt_bind_result(stmt, bind_array); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(buf1_len == strlen(cp1251)); + DIE_UNLESS(buf2_len == strlen(cp1251)); + DIE_UNLESS(!memcmp(buf1, cp1251, buf1_len)); + DIE_UNLESS(!memcmp(buf2, cp1251, buf1_len)); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); + rc= mysql_query(mysql, "set names default"); + myquery(rc); +} + +/** + Bug#36004 mysql_stmt_prepare resets the list of warnings +*/ + +static void test_bug36004() +{ + int rc, warning_count= 0; + MYSQL_STMT *stmt; + + DBUG_ENTER("test_bug36004"); + myheader("test_bug36004"); + + rc= mysql_query(mysql, "drop table if exists inexistant"); + myquery(rc); + + DIE_UNLESS(mysql_warning_count(mysql) == 1); + query_int_variable(mysql, "@@warning_count", &warning_count); + DIE_UNLESS(warning_count); + + stmt= mysql_simple_prepare(mysql, "select 1"); + check_stmt(stmt); + + DIE_UNLESS(mysql_warning_count(mysql) == 0); + query_int_variable(mysql, "@@warning_count", &warning_count); + DIE_UNLESS(warning_count); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + DIE_UNLESS(mysql_warning_count(mysql) == 0); + mysql_stmt_close(stmt); + + query_int_variable(mysql, "@@warning_count", &warning_count); + DIE_UNLESS(warning_count); + + stmt= mysql_simple_prepare(mysql, "drop table if exists inexistant"); + check_stmt(stmt); + + query_int_variable(mysql, "@@warning_count", &warning_count); + DIE_UNLESS(warning_count == 0); + mysql_stmt_close(stmt); + + DBUG_VOID_RETURN; +} + /** - Bug#38486 Crash when using cursor protocol + Test that COM_REFRESH issues a implicit commit. */ +static void test_wl4284_1() +{ + int rc; + MYSQL_ROW row; + MYSQL_RES *result; + + DBUG_ENTER("test_wl4284_1"); + myheader("test_wl4284_1"); + + /* set AUTOCOMMIT to OFF */ + rc= mysql_autocommit(mysql, FALSE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS trans"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE trans (a INT) ENGINE= InnoDB"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO trans VALUES(1)"); + myquery(rc); + + rc= mysql_refresh(mysql, REFRESH_GRANT | REFRESH_TABLES); + myquery(rc); + + rc= mysql_rollback(mysql); + myquery(rc); + + rc= mysql_query(mysql, "SELECT * FROM trans"); + myquery(rc); + + result= mysql_use_result(mysql); + mytest(result); + + row= mysql_fetch_row(result); + mytest(row); + + mysql_free_result(result); + + /* set AUTOCOMMIT to ON */ + rc= mysql_autocommit(mysql, TRUE); + myquery(rc); + + rc= mysql_query(mysql, "DROP TABLE trans"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + static void test_bug38486(void) { MYSQL_STMT *stmt; @@ -16672,6 +17584,45 @@ static void test_bug38486(void) DBUG_VOID_RETURN; } + +/** + Bug# 33831 mysql_real_connect() should fail if + given an already connected MYSQL handle. +*/ + +static void test_bug33831(void) +{ + MYSQL *l_mysql; + + DBUG_ENTER("test_bug33831"); + + if (!(l_mysql= mysql_client_init(NULL))) + { + myerror("mysql_client_init() failed"); + DIE_UNLESS(0); + } + if (!(mysql_real_connect(l_mysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0))) + { + myerror("connection failed"); + DIE_UNLESS(0); + } + + if (mysql_real_connect(l_mysql, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, 0)) + { + myerror("connection should have failed"); + DIE_UNLESS(0); + } + + mysql_close(l_mysql); + + DBUG_VOID_RETURN; +} + + static void test_bug40365(void) { uint rc, i; @@ -16750,6 +17701,8 @@ static void test_bug40365(void) DIE_UNLESS(tm[i].day == 0); } mysql_stmt_close(stmt); + rc= mysql_commit(mysql); + myquery(rc); DBUG_VOID_RETURN; } @@ -16776,7 +17729,8 @@ static void test_bug43560(void) const char* values[] = {"eins", "zwei", "drei", "viele", NULL}; const char insert_str[] = "INSERT INTO t1 (c2) VALUES (?)"; unsigned long length; - + const unsigned int drop_db= opt_drop_db; + DBUG_ENTER("test_bug43560"); myheader("test_bug43560"); @@ -16845,9 +17799,11 @@ static void test_bug43560(void) rc= mysql_stmt_execute(stmt); DIE_UNLESS(rc && mysql_stmt_errno(stmt) == CR_SERVER_LOST); - client_disconnect(conn, 0); + opt_drop_db= 0; + client_disconnect(conn); rc= mysql_query(mysql, "DROP TABLE t1"); myquery(rc); + opt_drop_db= drop_db; DBUG_VOID_RETURN; } @@ -17096,43 +18052,6 @@ static void test_bug53371() } -static void test_bug53907() -{ - int rc; - uchar buf[] = "\x4test\x14../client_test_db/t1"; - - myheader("test_bug53907"); - - rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); - myquery(rc); - rc= mysql_query(mysql, "DROP DATABASE IF EXISTS bug53907"); - myquery(rc); - rc= mysql_query(mysql, "DROP USER 'testbug'@localhost"); - - rc= mysql_query(mysql, "CREATE TABLE t1 (a INT)"); - myquery(rc); - rc= mysql_query(mysql, "CREATE DATABASE bug53907"); - myquery(rc); - rc= mysql_query(mysql, "GRANT SELECT ON bug53907.* to 'testbug'@localhost"); - myquery(rc); - - rc= mysql_change_user(mysql, "testbug", NULL, "bug53907"); - myquery(rc); - - rc= simple_command(mysql, COM_TABLE_DUMP, buf, sizeof(buf), 0); - fprintf(stderr, ">>>>>>>>> %d\n", mysql_errno(mysql)); - DIE_UNLESS(mysql_errno(mysql) == 1103); /* ER_WRONG_TABLE_NAME */ - - rc= mysql_change_user(mysql, opt_user, opt_password, current_db); - myquery(rc); - rc= mysql_query(mysql, "DROP TABLE t1"); - myquery(rc); - rc= mysql_query(mysql, "DROP DATABASE bug53907"); - myquery(rc); - rc= mysql_query(mysql, "DROP USER 'testbug'@localhost"); - myquery(rc); -} - /** Bug#42373: libmysql can mess a connection at connect @@ -17392,7 +18311,7 @@ static void test_bug47485() static void test_bug58036() { MYSQL *conn; - DBUG_ENTER("test_bug47485"); + DBUG_ENTER("test_bug58036"); myheader("test_bug58036"); /* Part1: try to connect with ucs2 client character set */ @@ -17454,6 +18373,116 @@ static void test_bug58036() /* + Bug#49972: Crash in prepared statements. + + The following case lead to a server crash: + - Use binary protocol; + - Prepare a statement with OUT-parameter; + - Execute the statement; + - Cause re-prepare of the statement (change dependencies); + - Execute the statement again -- crash here. +*/ + +static void test_bug49972() +{ + int rc; + MYSQL_STMT *stmt; + + MYSQL_BIND in_param_bind; + MYSQL_BIND out_param_bind; + int int_data; + my_bool is_null; + + DBUG_ENTER("test_bug49972"); + myheader("test_bug49972"); + + rc= mysql_query(mysql, "DROP FUNCTION IF EXISTS f1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE FUNCTION f1() RETURNS INT RETURN 1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE PROCEDURE p1(IN a INT, OUT b INT) SET b = a"); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "CALL p1((SELECT f1()), ?)"); + check_stmt(stmt); + + bzero((char *) &in_param_bind, sizeof (in_param_bind)); + + in_param_bind.buffer_type= MYSQL_TYPE_LONG; + in_param_bind.buffer= (char *) &int_data; + in_param_bind.length= 0; + in_param_bind.is_null= 0; + + rc= mysql_stmt_bind_param(stmt, &in_param_bind); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + { + bzero(&out_param_bind, sizeof (out_param_bind)); + + out_param_bind.buffer_type= MYSQL_TYPE_LONG; + out_param_bind.is_null= &is_null; + out_param_bind.buffer= &int_data; + out_param_bind.buffer_length= sizeof (int_data); + + rc= mysql_stmt_bind_result(stmt, &out_param_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + rc= mysql_stmt_fetch(stmt); + DBUG_ASSERT(rc == MYSQL_NO_DATA); + + mysql_stmt_next_result(stmt); + mysql_stmt_fetch(stmt); + } + + rc= mysql_query(mysql, "DROP FUNCTION f1"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE FUNCTION f1() RETURNS INT RETURN 1"); + myquery(rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + { + bzero(&out_param_bind, sizeof (out_param_bind)); + + out_param_bind.buffer_type= MYSQL_TYPE_LONG; + out_param_bind.is_null= &is_null; + out_param_bind.buffer= &int_data; + out_param_bind.buffer_length= sizeof (int_data); + + rc= mysql_stmt_bind_result(stmt, &out_param_bind); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + rc= mysql_stmt_fetch(stmt); + DBUG_ASSERT(rc == MYSQL_NO_DATA); + + mysql_stmt_next_result(stmt); + mysql_stmt_fetch(stmt); + } + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP PROCEDURE p1"); + myquery(rc); + + rc= mysql_query(mysql, "DROP FUNCTION f1"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + +/* Bug #56976: Severe Denial Of Service in prepared statements */ static void test_bug56976() @@ -17492,7 +18521,7 @@ static void test_bug56976() check_execute(stmt, rc); } - my_free(long_buffer, MYF(0)); + my_free(long_buffer); rc= mysql_stmt_execute(stmt); DIE_UNLESS(rc && mysql_stmt_errno(stmt) == ER_UNKNOWN_ERROR); @@ -17564,15 +18593,262 @@ static void test_progress_reporting() myquery(rc); rc= mysql_query(conn, "set @@global.progress_report_time=@save"); myquery(rc); - client_disconnect(conn, 0); + mysql_close(conn); +} + +/** + MDEV-3885 - connection suicide via mysql_kill() causes assertion in server +*/ + +static void test_mdev3885() +{ + int rc; + MYSQL *conn; + + myheader("test_mdev3885"); + conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0); + rc= mysql_kill(conn, mysql_thread_id(conn)); + DIE_UNLESS(rc); + mysql_close(conn); +} + + +/** + Bug#57058 SERVER_QUERY_WAS_SLOW not wired up. +*/ + +static void test_bug57058() +{ + MYSQL_RES *res; + int rc; + + DBUG_ENTER("test_bug57058"); + myheader("test_bug57058"); + + rc= mysql_query(mysql, "set @@session.long_query_time=0.1"); + myquery(rc); + + DIE_UNLESS(!(mysql->server_status & SERVER_QUERY_WAS_SLOW)); + + rc= mysql_query(mysql, "select sleep(1)"); + myquery(rc); + + /* + Important: the flag is sent in the last EOF packet of + the query, the one which ends the result. Read the + result to see the "slow" status. + */ + res= mysql_store_result(mysql); + + DIE_UNLESS(mysql->server_status & SERVER_QUERY_WAS_SLOW); + + mysql_free_result(res); + + rc= mysql_query(mysql, "set @@session.long_query_time=default"); + myquery(rc); + + DBUG_VOID_RETURN; +} + + +/** + Bug#11766854: 60075: MYSQL_LOAD_CLIENT_PLUGIN DOESN'T CLEAR ERROR +*/ + +static void test_bug11766854() +{ + struct st_mysql_client_plugin *plugin; + + DBUG_ENTER("test_bug11766854"); + myheader("test_bug11766854"); + + plugin= mysql_load_plugin(mysql, "foo", -1, 0); + DIE_UNLESS(plugin == 0); + + plugin= mysql_load_plugin(mysql, "qa_auth_client", -1, 0); + DIE_UNLESS(plugin != 0); + DIE_IF(mysql_errno(mysql)); + + DBUG_VOID_RETURN; +} + +/** + Bug#12337762: 60075: MYSQL_LIST_FIELDS() RETURNS WRONG CHARSET FOR + CHAR/VARCHAR/TEXT COLUMNS IN VIEWS +*/ +static void test_bug12337762() +{ + int rc,i=0; + MYSQL_RES *result; + MYSQL_FIELD *field; + unsigned int tab_charsetnr[3]= {0}; + + DBUG_ENTER("test_bug12337762"); + myheader("test_bug12337762"); + + /* + Creating table with specific charset. + */ + rc= mysql_query(mysql, "drop table if exists charset_tab"); + rc= mysql_query(mysql, "create table charset_tab("\ + "txt1 varchar(32) character set Latin1,"\ + "txt2 varchar(32) character set Latin1 collate latin1_bin,"\ + "txt3 varchar(32) character set utf8 collate utf8_bin"\ + ")"); + + DIE_UNLESS(rc == 0); + DIE_IF(mysql_errno(mysql)); + + /* + Creating view from table created earlier. + */ + rc= mysql_query(mysql, "drop view if exists charset_view"); + rc= mysql_query(mysql, "create view charset_view as "\ + "select * from charset_tab;"); + DIE_UNLESS(rc == 0); + DIE_IF(mysql_errno(mysql)); + + /* + Checking field information for table. + */ + result= mysql_list_fields(mysql, "charset_tab", NULL); + DIE_IF(mysql_errno(mysql)); + i=0; + while((field= mysql_fetch_field(result))) + { + printf("field name %s\n", field->name); + printf("field table %s\n", field->table); + printf("field type %d\n", field->type); + printf("field charset %d\n", field->charsetnr); + tab_charsetnr[i++]= field->charsetnr; + printf("\n"); + } + mysql_free_result(result); + + /* + Checking field information for view. + */ + result= mysql_list_fields(mysql, "charset_view", NULL); + DIE_IF(mysql_errno(mysql)); + i=0; + while((field= mysql_fetch_field(result))) + { + printf("field name %s\n", field->name); + printf("field table %s\n", field->table); + printf("field type %d\n", field->type); + printf("field charset %d\n", field->charsetnr); + printf("\n"); + /* + charset value for field must be same for both, view and table. + */ + DIE_UNLESS(field->charsetnr == tab_charsetnr[i++]); + } + mysql_free_result(result); + + DBUG_VOID_RETURN; } /* - Bug#13001491: MYSQL_REFRESH CRASHES WHEN STORED ROUTINES ARE RUN - CONCURRENTLY. + BUG 11754979 - 46675: ON DUPLICATE KEY UPDATE AND UPDATECOUNT() POSSIBLY WRONG */ +static void test_bug11754979() +{ + MYSQL* conn; + DBUG_ENTER("test_bug11754979"); + + myheader("test_bug11754979"); + DIE_UNLESS((conn= mysql_client_init(NULL))); + DIE_UNLESS(mysql_real_connect(conn, opt_host, opt_user, + opt_password, opt_db ? opt_db:"test", opt_port, + opt_unix_socket, CLIENT_FOUND_ROWS)); + myquery(mysql_query(conn, "DROP TABLE IF EXISTS t1")); + myquery(mysql_query(conn, "CREATE TABLE t1(id INT, label CHAR(1), PRIMARY KEY(id))")); + myquery(mysql_query(conn, "INSERT INTO t1(id, label) VALUES (1, 'a')")); + myquery(mysql_query(conn, "INSERT INTO t1(id, label) VALUES (1, 'a') " + "ON DUPLICATE KEY UPDATE id = 4")); + DIE_UNLESS(mysql_affected_rows(conn) == 2); + myquery(mysql_query(conn, "DROP TABLE t1")); + mysql_close(conn); + + DBUG_VOID_RETURN; +} + +static void test_ps_sp_out_params() +{ + MYSQL *my; + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + char buffer[20]; + int status, rc; + + myheader("test_ps_sp_out_params"); + my= mysql_client_init(NULL); + + if (!mysql_real_connect(my, opt_host, opt_user, + opt_password, current_db, opt_port, + opt_unix_socket, CLIENT_MULTI_RESULTS)) + DIE("mysql_real_connect failed"); + + rc= mysql_query(my, "DROP PROCEDURE IF EXISTS p1"); + myquery(rc); + + rc= mysql_query(my, + "CREATE PROCEDURE p1(OUT out_param VARCHAR(19)) " + "BEGIN" + " SELECT 'foo' FROM DUAL;" + " SET out_param='foo';" + " SELECT 'foo' FROM DUAL;" + "END"); + myquery(rc); + + stmt= mysql_stmt_init(my); + + rc= mysql_stmt_prepare(stmt, "CALL P1(?)", 10); + DIE_UNLESS(rc==0); + + DIE_UNLESS(mysql_stmt_param_count(stmt) == 1); + + memset(bind, 0, sizeof(MYSQL_BIND)); + bind[0].buffer= buffer; + bind[0].buffer_length= sizeof(buffer); + bind[0].buffer_type= MYSQL_TYPE_STRING; + + mysql_stmt_bind_param(stmt, bind); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + do { + if (mysql_stmt_field_count(stmt)) + { + /* since server sends a status packet at the end, + there must follow at least one additional packet */ + DIE_UNLESS(mysql_more_results(stmt->mysql)); + + mysql_stmt_bind_result(stmt, bind); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc== 0); + + DIE_UNLESS(strcmp(buffer, "foo") == 0); + } + status= mysql_stmt_next_result(stmt); + } while (status == 0); + + rc= mysql_stmt_reset(stmt); + DIE_UNLESS(rc== 0); + + mysql_stmt_close(stmt); + mysql_close(my); + + printf("end\n"); +} + +/* + Bug#13001491: MYSQL_REFRESH CRASHES WHEN STORED ROUTINES ARE RUN CONCURRENTLY. +*/ static void test_bug13001491() { int rc; @@ -17920,6 +19196,8 @@ static struct my_tests_st my_tests[]= { { "test_bug8378", test_bug8378 }, { "test_bug8722", test_bug8722 }, { "test_bug8880", test_bug8880 }, + { "test_open_cursor_prepared_statement_query_cache", + test_open_cursor_prepared_statement_query_cache }, { "test_bug9159", test_bug9159 }, { "test_bug9520", test_bug9520 }, { "test_bug9478", test_bug9478 }, @@ -17983,26 +19261,40 @@ static struct my_tests_st my_tests[]= { { "test_bug20023", test_bug20023 }, { "test_bug45010", test_bug45010 }, { "test_bug53371", test_bug53371 }, - { "test_bug53907", test_bug53907 }, { "test_bug31418", test_bug31418 }, { "test_bug31669", test_bug31669 }, { "test_bug28386", test_bug28386 }, { "test_wl4166_1", test_wl4166_1 }, { "test_wl4166_2", test_wl4166_2 }, + { "test_wl4166_3", test_wl4166_3 }, + { "test_wl4166_4", test_wl4166_4 }, + { "test_bug36004", test_bug36004 }, + { "test_wl4284_1", test_wl4284_1 }, + { "test_wl4435", test_wl4435 }, + { "test_wl4435_2", test_wl4435_2 }, + { "test_wl4435_3", test_wl4435_3 }, { "test_bug38486", test_bug38486 }, + { "test_bug33831", test_bug33831 }, { "test_bug40365", test_bug40365 }, { "test_bug43560", test_bug43560 }, { "test_bug36326", test_bug36326 }, { "test_bug41078", test_bug41078 }, { "test_bug44495", test_bug44495 }, + { "test_bug49972", test_bug49972 }, { "test_bug42373", test_bug42373 }, { "test_bug54041", test_bug54041 }, { "test_bug47485", test_bug47485 }, { "test_bug58036", test_bug58036 }, + { "test_bug57058", test_bug57058 }, { "test_bug56976", test_bug56976 }, + { "test_mdev3885", test_mdev3885 }, + { "test_bug11766854", test_bug11766854 }, + { "test_bug12337762", test_bug12337762 }, { "test_progress_reporting", test_progress_reporting }, + { "test_bug11754979", test_bug11754979 }, { "test_bug13001491", test_bug13001491 }, { "test_mdev4326", test_mdev4326 }, + { "test_ps_sp_out_params", test_ps_sp_out_params }, { 0, 0 } }; diff --git a/tests/nonblock-wrappers.h b/tests/nonblock-wrappers.h new file mode 100644 index 00000000000..3ed470b3400 --- /dev/null +++ b/tests/nonblock-wrappers.h @@ -0,0 +1,516 @@ +/* + Copyright 2011 Kristian Nielsen and Monty Program Ab + + This file is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + Wrappers that re-implement the normal blocking libmysql API calls in terms + of the non-blocking API calls and explicit waiting. + + Used to test the non-blocking calls using mysql_client_test. +*/ + +#ifndef __WIN__ +#include <poll.h> +#else +#include <WinSock2.h> +#endif + +/* + Run the appropriate poll() syscall to wait for the event that libmysql + requested. Return which event(s) occured. +*/ +static int +wait_for_mysql(MYSQL *mysql, int status) +{ +#ifdef __WIN__ + fd_set rs, ws, es; + int res; + struct timeval tv, *timeout; + my_socket s= mysql_get_socket(mysql); + FD_ZERO(&rs); + FD_ZERO(&ws); + FD_ZERO(&es); + if (status & MYSQL_WAIT_READ) + FD_SET(s, &rs); + if (status & MYSQL_WAIT_WRITE) + FD_SET(s, &ws); + if (status & MYSQL_WAIT_EXCEPT) + FD_SET(s, &es); + if (status & MYSQL_WAIT_TIMEOUT) + { + tv.tv_sec= mysql_get_timeout_value(mysql); + tv.tv_usec= 0; + timeout= &tv; + } + else + timeout= NULL; + res= select(1, &rs, &ws, &es, timeout); + if (res == 0) + return MYSQL_WAIT_TIMEOUT; + else if (res == SOCKET_ERROR) + return MYSQL_WAIT_TIMEOUT; + else + { + int status= 0; + if (FD_ISSET(s, &rs)) + status|= MYSQL_WAIT_READ; + if (FD_ISSET(s, &ws)) + status|= MYSQL_WAIT_WRITE; + if (FD_ISSET(s, &es)) + status|= MYSQL_WAIT_EXCEPT; + return status; + } +#else + struct pollfd pfd; + int timeout; + int res; + + pfd.fd= mysql_get_socket(mysql); + pfd.events= + (status & MYSQL_WAIT_READ ? POLLIN : 0) | + (status & MYSQL_WAIT_WRITE ? POLLOUT : 0) | + (status & MYSQL_WAIT_EXCEPT ? POLLPRI : 0); + if (status & MYSQL_WAIT_TIMEOUT) + timeout= 1000*mysql_get_timeout_value(mysql); + else + timeout= -1; + do { + res= poll(&pfd, 1, timeout); + /* + In a real event framework, we should re-compute the timeout on getting + EINTR to account for the time elapsed before the interruption. + */ + } while (res < 0 && errno == EINTR); + if (res == 0) + return MYSQL_WAIT_TIMEOUT; + else if (res < 0) + return MYSQL_WAIT_TIMEOUT; + else + { + int status= 0; + if (pfd.revents & POLLIN) + status|= MYSQL_WAIT_READ; + if (pfd.revents & POLLOUT) + status|= MYSQL_WAIT_WRITE; + if (pfd.revents & POLLPRI) + status|= MYSQL_WAIT_EXCEPT; + return status; + } +#endif +} + + +/* + If WRAP_NONBLOCK_ENABLED is defined, it is a variable that can be used to + enable or disable the use of non-blocking API wrappers. If true the + non-blocking API will be used, if false the normal blocking API will be + called directly. +*/ +#ifdef WRAP_NONBLOCK_ENABLED +#define USE_BLOCKING(name__, invoke_blocking__) \ + if (!(WRAP_NONBLOCK_ENABLED)) return name__ invoke_blocking__; +#define USE_BLOCKING_VOID_RETURN(name__, invoke__) \ + if (!(WRAP_NONBLOCK_ENABLED)) { name__ invoke__; return; } +#else +#define USE_BLOCKING(name__, invoke_blocking__) +#define USE_BLOCKING_VOID_RETURN(name__, invoke__) +#endif + +/* + I would preferably have declared the wrappers static. + However, if we do so, compilers will warn about definitions not used, and + with -Werror this breaks compilation :-( +*/ +#define MK_WRAPPER(ret_type__, name__, decl__, invoke__, invoke_blocking__, cont_arg__, mysql__) \ +ret_type__ wrap_ ## name__ decl__ \ +{ \ + ret_type__ res; \ + int status; \ + USE_BLOCKING(name__, invoke_blocking__) \ + status= name__ ## _start invoke__; \ + while (status) \ + { \ + status= wait_for_mysql(mysql__, status); \ + status= name__ ## _cont(&res, cont_arg__, status); \ + } \ + return res; \ +} + +#define MK_WRAPPER_VOID_RETURN(name__, decl__, invoke__, cont_arg__, mysql__) \ +void wrap_ ## name__ decl__ \ +{ \ + int status; \ + USE_BLOCKING_VOID_RETURN(name__, invoke__) \ + status= name__ ## _start invoke__; \ + while (status) \ + { \ + status= wait_for_mysql(mysql__, status); \ + status= name__ ## _cont(cont_arg__, status); \ + } \ +} + +MK_WRAPPER( + MYSQL *, + mysql_real_connect, + (MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag), + (&res, mysql, host, user, passwd, db, port, unix_socket, clientflag), + (mysql, host, user, passwd, db, port, unix_socket, clientflag), + mysql, + mysql) + + +MK_WRAPPER( + int, + mysql_real_query, + (MYSQL *mysql, const char *stmt_str, unsigned long length), + (&res, mysql, stmt_str, length), + (mysql, stmt_str, length), + mysql, + mysql) + +MK_WRAPPER( + MYSQL_ROW, + mysql_fetch_row, + (MYSQL_RES *result), + (&res, result), + (result), + result, + result->handle) + +MK_WRAPPER( + int, + mysql_set_character_set, + (MYSQL *mysql, const char *csname), + (&res, mysql, csname), + (mysql, csname), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_select_db, + (MYSQL *mysql, const char *db), + (&res, mysql, db), + (mysql, db), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_send_query, + (MYSQL *mysql, const char *q, unsigned long length), + (&res, mysql, q, length), + (mysql, q, length), + mysql, + mysql) + +MK_WRAPPER( + MYSQL_RES *, + mysql_store_result, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER_VOID_RETURN( + mysql_free_result, + (MYSQL_RES *result), + (result), + result, + result->handle) + +MK_WRAPPER_VOID_RETURN( + mysql_close, + (MYSQL *sock), + (sock), + sock, + sock) + +MK_WRAPPER( + my_bool, + mysql_change_user, + (MYSQL *mysql, const char *user, const char *passwd, const char *db), + (&res, mysql, user, passwd, db), + (mysql, user, passwd, db), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_query, + (MYSQL *mysql, const char *q), + (&res, mysql, q), + (mysql, q), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_shutdown, + (MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level), + (&res, mysql, shutdown_level), + (mysql, shutdown_level), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_dump_debug_info, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_refresh, + (MYSQL *mysql, unsigned int refresh_options), + (&res, mysql, refresh_options), + (mysql, refresh_options), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_kill, + (MYSQL *mysql, unsigned long pid), + (&res, mysql, pid), + (mysql, pid), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_set_server_option, + (MYSQL *mysql, enum enum_mysql_set_option option), + (&res, mysql, option), + (mysql, option), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_ping, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + const char *, + mysql_stat, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + MYSQL_RES *, + mysql_list_dbs, + (MYSQL *mysql, const char *wild), + (&res, mysql, wild), + (mysql, wild), + mysql, + mysql) + +MK_WRAPPER( + MYSQL_RES *, + mysql_list_tables, + (MYSQL *mysql, const char *wild), + (&res, mysql, wild), + (mysql, wild), + mysql, + mysql) + +MK_WRAPPER( + MYSQL_RES *, + mysql_list_processes, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + MYSQL_RES *, + mysql_list_fields, + (MYSQL *mysql, const char *table, const char *wild), + (&res, mysql, table, wild), + (mysql, table, wild), + mysql, + mysql) + +MK_WRAPPER( + my_bool, + mysql_read_query_result, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_stmt_prepare, + (MYSQL_STMT *stmt, const char *query, unsigned long length), + (&res, stmt, query, length), + (stmt, query, length), + stmt, + stmt->mysql) + +MK_WRAPPER( + int, + mysql_stmt_execute, + (MYSQL_STMT *stmt), + (&res, stmt), + (stmt), + stmt, + stmt->mysql) + +MK_WRAPPER( + int, + mysql_stmt_fetch, + (MYSQL_STMT *stmt), + (&res, stmt), + (stmt), + stmt, + stmt->mysql) + +MK_WRAPPER( + int, + mysql_stmt_store_result, + (MYSQL_STMT *stmt), + (&res, stmt), + (stmt), + stmt, + stmt->mysql) + +MK_WRAPPER( + my_bool, + mysql_stmt_close, + (MYSQL_STMT *stmt), + (&res, stmt), + (stmt), + stmt, + stmt->mysql) + +MK_WRAPPER( + my_bool, + mysql_stmt_reset, + (MYSQL_STMT *stmt), + (&res, stmt), + (stmt), + stmt, + stmt->mysql) + +MK_WRAPPER( + my_bool, + mysql_stmt_free_result, + (MYSQL_STMT *stmt), + (&res, stmt), + (stmt), + stmt, + stmt->mysql) + +MK_WRAPPER( + my_bool, + mysql_stmt_send_long_data, + (MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long length), + (&res, stmt, param_number, data, length), + (stmt, param_number, data, length), + stmt, + stmt->mysql) + +MK_WRAPPER( + my_bool, + mysql_commit, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + my_bool, + mysql_rollback, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + my_bool, + mysql_autocommit, + (MYSQL *mysql, my_bool auto_mode), + (&res, mysql, auto_mode), + (mysql, auto_mode), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_next_result, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +#undef USE_BLOCKING +#undef MK_WRAPPER +#undef MK_WRAPPER_VOID_RETURN + + +#define mysql_real_connect wrap_mysql_real_connect +#define mysql_real_query wrap_mysql_real_query +#define mysql_fetch_row wrap_mysql_fetch_row +#define mysql_set_character_set wrap_mysql_set_character_set +#define mysql_select_db wrap_mysql_select_db +#define mysql_send_query wrap_mysql_send_query +#define mysql_store_result wrap_mysql_store_result +#define mysql_free_result wrap_mysql_free_result +#define mysql_close wrap_mysql_close +#define mysql_change_user wrap_mysql_change_user +#define mysql_query wrap_mysql_query +#define mysql_shutdown wrap_mysql_shutdown +#define mysql_dump_debug_info wrap_mysql_dump_debug_info +#define mysql_refresh wrap_mysql_refresh +#define mysql_kill wrap_mysql_kill +#define mysql_set_server_option wrap_mysql_set_server_option +#define mysql_ping wrap_mysql_ping +#define mysql_stat wrap_mysql_stat +#define mysql_list_dbs wrap_mysql_list_dbs +#define mysql_list_tables wrap_mysql_list_tables +#define mysql_list_processes wrap_mysql_list_processes +#define mysql_list_fields wrap_mysql_list_fields +#define mysql_read_query_result wrap_mysql_read_query_result +#define mysql_stmt_prepare wrap_mysql_stmt_prepare +#define mysql_stmt_execute wrap_mysql_stmt_execute +#define mysql_stmt_fetch wrap_mysql_stmt_fetch +#define mysql_stmt_store_result wrap_mysql_stmt_store_result +#define mysql_stmt_close wrap_mysql_stmt_close +#define mysql_stmt_reset wrap_mysql_stmt_reset +#define mysql_stmt_free_result wrap_mysql_stmt_free_result +#define mysql_stmt_send_long_data wrap_mysql_stmt_send_long_data +#define mysql_commit wrap_mysql_commit +#define mysql_rollback wrap_mysql_rollback +#define mysql_autocommit wrap_mysql_autocommit +#define mysql_next_result wrap_mysql_next_result diff --git a/tests/pmail.pl b/tests/pmail.pl index 02d5d60ac0f..38905832069 100755 --- a/tests/pmail.pl +++ b/tests/pmail.pl @@ -1,4 +1,20 @@ #!/usr/bin/perl -w + +# Copyright (C) 2000, 2005 MySQL 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; version 2 of the License. +# +# 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 + # # Prints mails to standard output # diff --git a/tests/rename_test.pl b/tests/rename_test.pl index edf3216a62f..23fc33c9095 100755 --- a/tests/rename_test.pl +++ b/tests/rename_test.pl @@ -1,4 +1,20 @@ #!/usr/bin/perl -w + +# Copyright (C) 2000, 2001 MySQL 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; version 2 of the License. +# +# 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 is a test with uses processes to insert, select and drop tables. # diff --git a/tests/table_types.pl b/tests/table_types.pl index 4dbcdcb975c..23d26215abe 100755 --- a/tests/table_types.pl +++ b/tests/table_types.pl @@ -1,5 +1,19 @@ #!/usr/bin/perl -# + +# Copyright (C) 2000, 2003 MySQL 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; version 2 of the License. +# +# 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 use DBI; use Benchmark; diff --git a/tests/test_delayed_insert.pl b/tests/test_delayed_insert.pl index c7a8f0ca4b7..5046c4fb580 100755 --- a/tests/test_delayed_insert.pl +++ b/tests/test_delayed_insert.pl @@ -1,5 +1,20 @@ #!/usr/bin/perl -w +# Copyright (C) 2000, 2001 MySQL 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; version 2 of the License. +# +# 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 is a test for INSERT DELAYED # diff --git a/tests/thread_test.c b/tests/thread_test.c index 0944cbc0970..bf0fb8ea2c0 100644 --- a/tests/thread_test.c +++ b/tests/thread_test.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 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 @@ -11,19 +11,10 @@ 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 */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <my_global.h> -#ifndef THREAD - -int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) -{ - printf("This test must be compiled with multithread support to work\n"); - exit(1); -} -#else - #include <my_sys.h> #include <my_pthread.h> #include "mysql.h" @@ -77,7 +68,7 @@ end: mysql_close(mysql); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */ + pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */ pthread_mutex_unlock(&LOCK_thread_count); pthread_exit(0); return 0; @@ -88,36 +79,36 @@ static struct my_option my_long_options[] = { {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"database", 'D', "Database to use", (uchar**) &database, (uchar**) &database, + {"database", 'D', "Database to use", &database, &database, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"host", 'h', "Connect to host", (uchar**) &host, (uchar**) &host, 0, GET_STR, + {"host", 'h', "Connect to host", &host, &host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to use when connecting to server. If password is not given it's asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"user", 'u', "User for login if not current user", (uchar**) &user, - (uchar**) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"user", 'u', "User for login if not current user", &user, + &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"verbose", 'v', "Write some progress indicators", (uchar**) &verbose, - (uchar**) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"query", 'Q', "Query to execute in each threads", (uchar**) &query, - (uchar**) &query, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"verbose", 'v', "Write some progress indicators", &verbose, + &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"query", 'Q', "Query to execute in each threads", &query, + &query, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection or 0 for default to, in " "order of preference, my.cnf, $MYSQL_TCP_PORT, " #if MYSQL_PORT_DEFAULT == 0 "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - (uchar**) &tcp_port, - (uchar**) &tcp_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, - {"socket", 'S', "Socket file to use for connection", (uchar**) &unix_socket, - (uchar**) &unix_socket, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + &tcp_port, + &tcp_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, + {"socket", 'S', "Socket file to use for connection", &unix_socket, + &unix_socket, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"test-count", 'c', "Run test count times (default %d)", - (uchar**) &number_of_tests, (uchar**) &number_of_tests, 0, GET_UINT, + &number_of_tests, &number_of_tests, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0}, {"thread-count", 't', "Number of threads to start", - (uchar**) &number_of_threads, (uchar**) &number_of_threads, 0, GET_UINT, + &number_of_threads, &number_of_threads, 0, GET_UINT, REQUIRED_ARG, 2, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -151,7 +142,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'p': if (argument) { - my_free(password, MYF(MY_ALLOW_ZERO_PTR)); + my_free(password); password= my_strdup(argument, MYF(MY_FAE)); while (*argument) *argument++= 'x'; /* Destroy argument */ } @@ -177,9 +168,8 @@ static void get_options(int argc, char **argv) { int ho_error; - load_defaults("my",load_default_groups,&argc,&argv); - - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) + if ((ho_error= load_defaults("my",load_default_groups,&argc,&argv)) || + (ho_error= handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); free_defaults(argv); @@ -256,4 +246,3 @@ int main(int argc, char **argv) return 0; /* Keep some compilers happy */ } -#endif /* THREAD */ diff --git a/tests/truncate.pl b/tests/truncate.pl index 57b50cf96b6..85e826fd4cd 100755 --- a/tests/truncate.pl +++ b/tests/truncate.pl @@ -1,4 +1,20 @@ #!/usr/bin/perl -w + +# Copyright (C) 2002 MySQL 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; version 2 of the License. +# +# 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 is a test with uses many processes to test a MySQL server. # |