Commit f4dc9215 authored by Andrei Elkin's avatar Andrei Elkin

merge from 5.5 repo.

parents aa103d02 88a74a16
......@@ -792,8 +792,11 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
goto end;
}
else
{
ce->print(result_file, print_event_info, TRUE);
if (head->error == -1)
goto err;
}
// If this binlog is not 3.23 ; why this test??
if (glob_description_event->binlog_version >= 3)
{
......@@ -844,6 +847,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
ce->print(result_file, print_event_info, TRUE);
my_free((void*)ce->fname);
delete ce;
if (head->error == -1)
goto err;
}
else
warning("Ignoring Execute_load_log_event as there is no "
......@@ -904,6 +909,12 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
{
convert_path_to_forward_slashes(fname);
exlq->print(result_file, print_event_info, fname);
if (head->error == -1)
{
if (fname)
my_free(fname);
goto err;
}
}
else
warning("Ignoring Execute_load_query since there is no "
......
......@@ -16,6 +16,7 @@
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/libmysqld/include
${CMAKE_SOURCE_DIR}/regex
${CMAKE_SOURCE_DIR}/tests
${READLINE_INCLUDE_DIR}
)
......
......@@ -433,7 +433,11 @@ size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args)
memset(buffz, '0', minimum_width - length2);
else
memset(buffz, ' ', minimum_width - length2);
my_b_write(info, buffz, minimum_width - length2);
if (my_b_write(info, buffz, minimum_width - length2))
{
my_afree(buffz);
goto err;
}
my_afree(buffz);
}
......
......@@ -2762,7 +2762,10 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
{
end= strxmov(buff, "# administrator command: ", NullS);
buff_len= (ulong) (end - buff);
my_b_write(&log_file, (uchar*) buff, buff_len);
DBUG_EXECUTE_IF("simulate_slow_log_write_error",
{DBUG_SET("+d,simulate_file_write_error");});
if(my_b_write(&log_file, (uchar*) buff, buff_len))
tmp_errno= errno;
}
if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) ||
my_b_write(&log_file, (uchar*) ";\n",2) ||
......
......@@ -6478,11 +6478,18 @@ void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info
{
Load_log_event::print(file, print_event_info,
!check_fname_outside_temp_buf());
/*
That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
SHOW BINLOG EVENTS we don't.
*/
my_b_printf(&cache, "#");
/**
reduce the size of io cache so that the write function is called
for every call to my_b_printf().
*/
DBUG_EXECUTE_IF ("simulate_create_event_write_error",
{(&cache)->write_pos= (&cache)->write_end;
DBUG_SET("+d,simulate_file_write_error");});
/*
That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
SHOW BINLOG EVENTS we don't.
*/
my_b_printf(&cache, "#");
}
my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len);
......@@ -7169,6 +7176,13 @@ void Execute_load_query_log_event::print(FILE* file,
Write_on_release_cache cache(&print_event_info->head_cache, file);
print_query_header(&cache, print_event_info);
/**
reduce the size of io cache so that the write function is called
for every call to my_b_printf().
*/
DBUG_EXECUTE_IF ("simulate_execute_event_write_error",
{(&cache)->write_pos= (&cache)->write_end;
DBUG_SET("+d,simulate_file_write_error");});
if (local_fname)
{
......
......@@ -271,7 +271,7 @@ class Deferred_log_events
public:
Deferred_log_events(Relay_log_info *rli);
~Deferred_log_events();
/* queue for exection at Query-log-event time prior the Query */;
/* queue for exection at Query-log-event time prior the Query */
int add(Log_event *ev);
bool is_empty();
bool execute(Relay_log_info *rli);
......
/* 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
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 */
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
#include <errmsg.h>
#include <my_getopt.h>
#include <m_string.h>
#include <mysqld_error.h>
#include <sql_common.h>
#include <mysql/client_plugin.h>
#define VER "2.1"
#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
#define MAX_KEY MAX_INDEXES
#define MAX_SERVER_ARGS 64
/* set default options */
static int opt_testcase = 0;
static char *opt_db= 0;
static char *opt_user= 0;
static char *opt_password= 0;
static char *opt_host= 0;
static char *opt_unix_socket= 0;
#ifdef HAVE_SMEM
static char *shared_memory_base_name= 0;
#endif
static unsigned int opt_port;
static my_bool tty_password= 0, opt_silent= 0;
static MYSQL *mysql= 0;
static char current_db[]= "client_test_db";
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 const char *opt_basedir= "./";
static const char *opt_vardir= "mysql-test/var";
static longlong opt_getopt_ll_test= 0;
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
};
static time_t start_time, end_time;
static double total_time;
const char *default_dbug_option= "d:t:o,/tmp/mysql_client_test.trace";
struct my_tests_st
{
const char *name;
void (*function)();
};
#define myheader(str) \
DBUG_PRINT("test", ("name: %s", str)); \
if (opt_silent < 2) \
{ \
fprintf(stdout, "\n\n#####################################\n"); \
fprintf(stdout, "%u of (%u/%u): %s", test_count++, iter_count, \
opt_count, str); \
fprintf(stdout, " \n#####################################\n"); \
}
#define myheader_r(str) \
DBUG_PRINT("test", ("name: %s", str)); \
if (!opt_silent) \
{ \
fprintf(stdout, "\n\n#####################################\n"); \
fprintf(stdout, "%s", str); \
fprintf(stdout, " \n#####################################\n"); \
}
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);
/*
Abort unless given experssion is non-zero.
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.
*/
#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);
}
#define myerror(msg) print_error(msg)
#define mysterror(stmt, msg) print_st_error(stmt, msg)
#define myquery(RES) \
{ \
int r= (RES); \
if (r) \
myerror(NULL); \
DIE_UNLESS(r == 0); \
}
#define myquery_r(r) \
{ \
if (r) \
myerror(NULL); \
DIE_UNLESS(r != 0); \
}
#define check_execute(stmt, r) \
{ \
if (r) \
mysterror(stmt, NULL); \
DIE_UNLESS(r == 0); \
}
#define check_execute_r(stmt, r) \
{ \
if (r) \
mysterror(stmt, NULL); \
DIE_UNLESS(r != 0); \
}
#define check_stmt(stmt) \
{ \
if ( stmt == 0) \
myerror(NULL); \
DIE_UNLESS(stmt != 0); \
}
#define check_stmt_r(stmt) \
{ \
if (stmt == 0) \
myerror(NULL); \
DIE_UNLESS(stmt == 0); \
}
#define mytest(x) if (!(x)) {myerror(NULL);DIE_UNLESS(FALSE);}
#define mytest_r(x) if ((x)) {myerror(NULL);DIE_UNLESS(FALSE);}
/* A workaround for Sun Forte 5.6 on Solaris x86 */
static int cmp_double(double *a, double *b)
{
return *a == *b;
}
/* Print the error message */
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);
}
}
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);
}
}
/*
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
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.
*/
#define mysql_init(A) Please use mysql_client_init instead of mysql_init
/* Check if the connection has InnoDB tables */
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;
}
/*
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;
}
/**
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
@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 (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");
return mysql;
}
/* Close the connection */
static void client_disconnect(MYSQL* mysql, my_bool drop_db)
{
static char query[MAX_TEST_QUERY_LENGTH];
myheader_r("client_disconnect");
if (mysql)
{
if (drop_db)
{
if (!opt_silent)
fprintf(stdout, "\n dropping the test database '%s' ...", current_db);
strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS);
mysql_query(mysql, query);
if (!opt_silent)
fprintf(stdout, "OK");
}
if (!opt_silent)
fprintf(stdout, "\n closing the connection ...");
mysql_close(mysql);
if (!opt_silent)
fprintf(stdout, "OK\n");
}
}
/* Print dashes */
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);
}
/* Print resultset metadata information */
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);
}
}
/* Process the result set */
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;
}
static int my_process_result(MYSQL *mysql_arg)
{
MYSQL_RES *result;
int row_count;
if (!(result= mysql_store_result(mysql_arg)))
return 0;
row_count= my_process_result_set(result);
mysql_free_result(result);
return row_count;
}
/* Process the statement result set */
#define MAX_RES_FIELDS 50
#define MAX_FIELD_DATA_SIZE 255
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;
}
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;
}
/* Prepare statement, execute, and process result set for given query */
int my_stmt_result(const char *buff)
{
MYSQL_STMT *stmt;
int row_count;
int rc;
if (!opt_silent)
fprintf(stdout, "\n\n %s", buff);
stmt= mysql_simple_prepare(mysql, buff);
check_stmt(stmt);
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
row_count= my_process_stmt_result(stmt);
mysql_stmt_close(stmt);
return row_count;
}
/* Print the total number of warnings and the warnings themselves. */
void my_process_warnings(MYSQL *conn, unsigned expected_warning_count)
{
MYSQL_RES *result;
int rc;
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_query(conn, "SHOW WARNINGS");
DIE_UNLESS(rc == 0);
result= mysql_store_result(conn);
mytest(result);
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)
{
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__)
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)
{
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))
{
fprintf(stderr, "Expected field length: %llu, got length: %lu\n",
expected_field_length, field->length);
DIE_UNLESS(field->length == expected_field_length);
}
if (def)
DIE_UNLESS(strcmp(field->def, def) == 0);
}
/* Utility function to verify the parameter count */
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);
}
/* Utility function to verify the total affected rows */
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);
}
/* Utility function to verify the total affected rows */
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);
}
/* Utility function to verify the total fields 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);
}
/* Utility function to execute a query using prepare-execute */
#ifndef EMBEDDED_LIBRARY
static void execute_prepare_query(const char *query, ulonglong exp_count)
{
MYSQL_STMT *stmt;
ulonglong affected_rows;
int rc;
stmt= mysql_simple_prepare(mysql, query);
check_stmt(stmt);
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);
DIE_UNLESS(affected_rows == exp_count);
mysql_stmt_close(stmt);
}
#endif
/*
Accepts arbitrary number of queries and runs them against the database.
Used to fill tables for each test.
*/
void fill_tables(const char **query_list, unsigned query_count)
{
int rc;
const char **query;
DBUG_ENTER("fill_tables");
for (query= query_list; query < query_list + query_count;
++query)
{
rc= mysql_query(mysql, *query);
myquery(rc);
}
DBUG_VOID_RETURN;
}
/*
All state of fetch from one statement: statement handle, out buffers,
fetch position.
See fetch_n for for the only use case.
*/
enum { MAX_COLUMN_LENGTH= 255 };
typedef struct st_stmt_fetch
{
const char *query;
unsigned stmt_no;
MYSQL_STMT *handle;
my_bool is_open;
MYSQL_BIND *bind_array;
char **out_data;
unsigned long *out_data_length;
unsigned column_count;
unsigned row_count;
} Stmt_fetch;
/*
Create statement handle, prepare it with statement, execute and allocate
fetch buffers.
*/
void stmt_fetch_init(Stmt_fetch *fetch, unsigned stmt_no_arg,
const char *query_arg)
{
unsigned long type= CURSOR_TYPE_READ_ONLY;
int rc;
unsigned i;
MYSQL_RES *metadata;
DBUG_ENTER("stmt_fetch_init");
/* Save query and statement number for error messages */
fetch->stmt_no= stmt_no_arg;
fetch->query= query_arg;
fetch->handle= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query));
check_execute(fetch->handle, rc);
/*
The attribute is sent to server on execute and asks to open read-only
for result set
*/
mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE,
(const void*) &type);
rc= mysql_stmt_execute(fetch->handle);
check_execute(fetch->handle, rc);
/* Find out total number of columns in result set */
metadata= mysql_stmt_result_metadata(fetch->handle);
fetch->column_count= mysql_num_fields(metadata);
mysql_free_result(metadata);
/*
Now allocate bind handles and buffers for output data:
calloc memory to reduce number of MYSQL_BIND members we need to
set up.
*/
fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) *
fetch->column_count);
fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count);
fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) *
fetch->column_count);
for (i= 0; i < fetch->column_count; ++i)
{
fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH);
fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING;
fetch->bind_array[i].buffer= fetch->out_data[i];
fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH;
fetch->bind_array[i].length= fetch->out_data_length + i;
}
mysql_stmt_bind_result(fetch->handle, fetch->bind_array);
fetch->row_count= 0;
fetch->is_open= TRUE;
/* Ready for reading rows */
DBUG_VOID_RETURN;
}
/* Fetch and print one row from cursor */
int stmt_fetch_fetch_row(Stmt_fetch *fetch)
{
int rc;
unsigned i;
DBUG_ENTER("stmt_fetch_fetch_row");
if ((rc= mysql_stmt_fetch(fetch->handle)) == 0)
{
++fetch->row_count;
if (!opt_silent)
printf("Stmt %d fetched row %d:\n", fetch->stmt_no, fetch->row_count);
for (i= 0; i < fetch->column_count; ++i)
{
fetch->out_data[i][fetch->out_data_length[i]]= '\0';
if (!opt_silent)
printf("column %d: %s\n", i+1, fetch->out_data[i]);
}
}
else
fetch->is_open= FALSE;
DBUG_RETURN(rc);
}
void stmt_fetch_close(Stmt_fetch *fetch)
{
unsigned i;
DBUG_ENTER("stmt_fetch_close");
for (i= 0; i < fetch->column_count; ++i)
free(fetch->out_data[i]);
free(fetch->out_data);
free(fetch->out_data_length);
free(fetch->bind_array);
mysql_stmt_close(fetch->handle);
DBUG_VOID_RETURN;
}
/*
For given array of queries, open query_count cursors and fetch
from them in simultaneous manner.
In case there was an error in one of the cursors, continue
reading from the rest.
*/
enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 };
my_bool fetch_n(const char **query_list, unsigned query_count,
enum fetch_type fetch_type)
{
unsigned open_statements= query_count;
int rc, error_count= 0;
Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) *
query_count);
Stmt_fetch *fetch;
DBUG_ENTER("fetch_n");
for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
{
/* Init will exit(1) in case of error */
stmt_fetch_init(fetch, fetch - fetch_array,
query_list[fetch - fetch_array]);
}
if (fetch_type == USE_STORE_RESULT)
{
for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
{
rc= mysql_stmt_store_result(fetch->handle);
check_execute(fetch->handle, rc);
}
}
while (open_statements)
{
for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
{
if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch)))
{
open_statements--;
/*
We try to fetch from the rest of the statements in case of
error
*/
if (rc != MYSQL_NO_DATA)
{
fprintf(stderr,
"Got error reading rows from statement %d,\n"
"query is: %s,\n"
"error message: %s", (int) (fetch - fetch_array),
fetch->query,
mysql_stmt_error(fetch->handle));
error_count++;
}
}
}
}
if (error_count)
fprintf(stderr, "Fetch FAILED");
else
{
unsigned total_row_count= 0;
for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
total_row_count+= fetch->row_count;
if (!opt_silent)
printf("Success, total rows fetched: %d\n", total_row_count);
}
for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
stmt_fetch_close(fetch);
free(fetch_array);
DBUG_RETURN(error_count != 0);
}
/* Separate thread query to test some cases */
static my_bool thread_query(const char *query)
{
MYSQL *l_mysql;
my_bool error;
error= 0;
if (!opt_silent)
fprintf(stdout, "\n in thread_query(%s)", query);
if (!(l_mysql= mysql_client_init(NULL)))
{
myerror("mysql_client_init() failed");
return 1;
}
if (!(mysql_real_connect(l_mysql, opt_host, opt_user,
opt_password, current_db, opt_port,
opt_unix_socket, 0)))
{
myerror("connection failed");
error= 1;
goto end;
}
l_mysql->reconnect= 1;
if (mysql_query(l_mysql, query))
{
fprintf(stderr, "Query failed (%s)\n", mysql_error(l_mysql));
error= 1;
goto end;
}
mysql_commit(l_mysql);
end:
mysql_close(l_mysql);
return error;
}
/*
Read and parse arguments and MySQL options from my.cnf
*/
static const char *client_test_load_default_groups[]= { "client", 0 };
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},
#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},
#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},
#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},
#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},
{"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("\
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);
}
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)
{
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 '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;
}
static void get_options(int *argc, char ***argv)
{
int 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;
}
/*
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");
}
}
/***************************************************************************
main routine
***************************************************************************/
int main(int argc, char **argv)
{
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, 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]);
mysql_server_end();
my_end(0);
exit(0);
}
/* Copyright (c) 2002, 2011, 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
......@@ -26,923 +26,57 @@
*/
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
#include <errmsg.h>
#include <my_getopt.h>
#include <m_string.h>
#include <mysqld_error.h>
#include <sql_common.h>
#include <mysql/client_plugin.h>
#define VER "2.1"
#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
#define MAX_KEY MAX_INDEXES
#define MAX_SERVER_ARGS 64
/* set default options */
static int opt_testcase = 0;
static char *opt_db= 0;
static char *opt_user= 0;
static char *opt_password= 0;
static char *opt_host= 0;
static char *opt_unix_socket= 0;
#ifdef HAVE_SMEM
static char *shared_memory_base_name= 0;
#endif
static unsigned int opt_port;
static my_bool tty_password= 0, opt_silent= 0;
static MYSQL *mysql= 0;
static char current_db[]= "client_test_db";
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 const char *opt_basedir= "./";
static const char *opt_vardir= "mysql-test/var";
static longlong opt_getopt_ll_test= 0;
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
};
static time_t start_time, end_time;
static double total_time;
const char *default_dbug_option= "d:t:o,/tmp/mysql_client_test.trace";
struct my_tests_st
{
const char *name;
void (*function)();
};
#define myheader(str) \
DBUG_PRINT("test", ("name: %s", str)); \
if (opt_silent < 2) \
{ \
fprintf(stdout, "\n\n#####################################\n"); \
fprintf(stdout, "%u of (%u/%u): %s", test_count++, iter_count, \
opt_count, str); \
fprintf(stdout, " \n#####################################\n"); \
}
#define myheader_r(str) \
DBUG_PRINT("test", ("name: %s", str)); \
if (!opt_silent) \
{ \
fprintf(stdout, "\n\n#####################################\n"); \
fprintf(stdout, "%s", str); \
fprintf(stdout, " \n#####################################\n"); \
}
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);
/*
Abort unless given experssion is non-zero.
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.
*/
#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);
}
#define myerror(msg) print_error(msg)
#define mysterror(stmt, msg) print_st_error(stmt, msg)
#define myquery(RES) \
{ \
int r= (RES); \
if (r) \
myerror(NULL); \
DIE_UNLESS(r == 0); \
}
#define myquery_r(r) \
{ \
if (r) \
myerror(NULL); \
DIE_UNLESS(r != 0); \
}
#define check_execute(stmt, r) \
{ \
if (r) \
mysterror(stmt, NULL); \
DIE_UNLESS(r == 0);\
}
#define check_execute_r(stmt, r) \
{ \
if (r) \
mysterror(stmt, NULL); \
DIE_UNLESS(r != 0);\
}
#define check_stmt(stmt) \
{ \
if ( stmt == 0) \
myerror(NULL); \
DIE_UNLESS(stmt != 0); \
}
#define check_stmt_r(stmt) \
{ \
if (stmt == 0) \
myerror(NULL);\
DIE_UNLESS(stmt == 0);\
}
#define mytest(x) if (!(x)) {myerror(NULL);DIE_UNLESS(FALSE);}
#define mytest_r(x) if ((x)) {myerror(NULL);DIE_UNLESS(FALSE);}
/* A workaround for Sun Forte 5.6 on Solaris x86 */
static int cmp_double(double *a, double *b)
{
return *a == *b;
}
/* Print the error message */
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);
}
}
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);
}
}
/*
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
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.
*/
#define mysql_init(A) Please use mysql_client_init instead of mysql_init
/* Check if the connection has InnoDB tables */
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;
}
/*
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;
}
/**
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
@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 (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");
return mysql;
}
/* Close the connection */
static void client_disconnect(MYSQL* mysql, my_bool drop_db)
{
static char query[MAX_TEST_QUERY_LENGTH];
myheader_r("client_disconnect");
if (mysql)
{
if (drop_db)
{
if (!opt_silent)
fprintf(stdout, "\n dropping the test database '%s' ...", current_db);
strxmov(query, "DROP DATABASE IF EXISTS ", current_db, NullS);
mysql_query(mysql, query);
if (!opt_silent)
fprintf(stdout, "OK");
}
if (!opt_silent)
fprintf(stdout, "\n closing the connection ...");
mysql_close(mysql);
if (!opt_silent)
fprintf(stdout, "OK\n");
}
}
/* Query processing */
static void client_query()
{
int rc;
myheader("client_query");
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
myquery(rc);
rc= mysql_query(mysql, "CREATE TABLE t1("
"id int primary key auto_increment, "
"name varchar(20))");
myquery(rc);
rc= mysql_query(mysql, "CREATE TABLE t1(id int, name varchar(20))");
myquery_r(rc);
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('mysql')");
myquery(rc);
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('monty')");
myquery(rc);
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('venu')");
myquery(rc);
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('deleted')");
myquery(rc);
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('deleted')");
myquery(rc);
rc= mysql_query(mysql, "UPDATE t1 SET name= 'updated' "
"WHERE name= 'deleted'");
myquery(rc);
rc= mysql_query(mysql, "UPDATE t1 SET id= 3 WHERE name= 'updated'");
myquery_r(rc);
myquery(mysql_query(mysql, "drop table t1"));
}
/* Print dashes */
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);
}
/* Print resultset metadata information */
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);
}
}
/* Process the result set */
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;
}
static int my_process_result(MYSQL *mysql_arg)
{
MYSQL_RES *result;
int row_count;
if (!(result= mysql_store_result(mysql_arg)))
return 0;
row_count= my_process_result_set(result);
mysql_free_result(result);
return row_count;
}
/* Process the statement result set */
#define MAX_RES_FIELDS 50
#define MAX_FIELD_DATA_SIZE 255
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;
}
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;
}
/* Prepare statement, execute, and process result set for given query */
int my_stmt_result(const char *buff)
{
MYSQL_STMT *stmt;
int row_count;
int rc;
if (!opt_silent)
fprintf(stdout, "\n\n %s", buff);
stmt= mysql_simple_prepare(mysql, buff);
check_stmt(stmt);
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
row_count= my_process_stmt_result(stmt);
mysql_stmt_close(stmt);
return row_count;
}
/* Print the total number of warnings and the warnings themselves. */
void my_process_warnings(MYSQL *conn, unsigned expected_warning_count)
{
MYSQL_RES *result;
int rc;
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_query(conn, "SHOW WARNINGS");
DIE_UNLESS(rc == 0);
result= mysql_store_result(conn);
mytest(result);
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)
{
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__)
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)
{
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))
{
fprintf(stderr, "Expected field length: %llu, got length: %lu\n",
expected_field_length, field->length);
DIE_UNLESS(field->length == expected_field_length);
}
if (def)
DIE_UNLESS(strcmp(field->def, def) == 0);
}
/* Utility function to verify the parameter count */
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);
}
/*
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.
*/
#include "mysql_client_fw.c"
/* Utility function to verify the total affected rows */
/* Query processing */
static void verify_st_affected_rows(MYSQL_STMT *stmt, ulonglong exp_count)
static void client_query()
{
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);
}
int rc;
/* Utility function to verify the total affected rows */
myheader("client_query");
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);
}
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
myquery(rc);
rc= mysql_query(mysql, "CREATE TABLE t1("
"id int primary key auto_increment, "
"name varchar(20))");
myquery(rc);
/* Utility function to verify the total fields count */
rc= mysql_query(mysql, "CREATE TABLE t1(id int, name varchar(20))");
myquery_r(rc);
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);
}
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('mysql')");
myquery(rc);
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('monty')");
myquery(rc);
/* Utility function to execute a query using prepare-execute */
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('venu')");
myquery(rc);
#ifndef EMBEDDED_LIBRARY
static void execute_prepare_query(const char *query, ulonglong exp_count)
{
MYSQL_STMT *stmt;
ulonglong affected_rows;
int rc;
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('deleted')");
myquery(rc);
stmt= mysql_simple_prepare(mysql, query);
check_stmt(stmt);
rc= mysql_query(mysql, "INSERT INTO t1(name) VALUES('deleted')");
myquery(rc);
rc= mysql_stmt_execute(stmt);
rc= mysql_query(mysql, "UPDATE t1 SET name= 'updated' "
"WHERE name= 'deleted'");
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);
rc= mysql_query(mysql, "UPDATE t1 SET id= 3 WHERE name= 'updated'");
myquery_r(rc);
DIE_UNLESS(affected_rows == exp_count);
mysql_stmt_close(stmt);
myquery(mysql_query(mysql, "drop table t1"));
}
#endif
/* Store result processing */
......@@ -985,267 +119,6 @@ static void client_use_result()
}
/*
Accepts arbitrary number of queries and runs them against the database.
Used to fill tables for each test.
*/
void fill_tables(const char **query_list, unsigned query_count)
{
int rc;
const char **query;
DBUG_ENTER("fill_tables");
for (query= query_list; query < query_list + query_count;
++query)
{
rc= mysql_query(mysql, *query);
myquery(rc);
}
DBUG_VOID_RETURN;
}
/*
All state of fetch from one statement: statement handle, out buffers,
fetch position.
See fetch_n for for the only use case.
*/
enum { MAX_COLUMN_LENGTH= 255 };
typedef struct st_stmt_fetch
{
const char *query;
unsigned stmt_no;
MYSQL_STMT *handle;
my_bool is_open;
MYSQL_BIND *bind_array;
char **out_data;
unsigned long *out_data_length;
unsigned column_count;
unsigned row_count;
} Stmt_fetch;
/*
Create statement handle, prepare it with statement, execute and allocate
fetch buffers.
*/
void stmt_fetch_init(Stmt_fetch *fetch, unsigned stmt_no_arg,
const char *query_arg)
{
unsigned long type= CURSOR_TYPE_READ_ONLY;
int rc;
unsigned i;
MYSQL_RES *metadata;
DBUG_ENTER("stmt_fetch_init");
/* Save query and statement number for error messages */
fetch->stmt_no= stmt_no_arg;
fetch->query= query_arg;
fetch->handle= mysql_stmt_init(mysql);
rc= mysql_stmt_prepare(fetch->handle, fetch->query, strlen(fetch->query));
check_execute(fetch->handle, rc);
/*
The attribute is sent to server on execute and asks to open read-only
for result set
*/
mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE,
(const void*) &type);
rc= mysql_stmt_execute(fetch->handle);
check_execute(fetch->handle, rc);
/* Find out total number of columns in result set */
metadata= mysql_stmt_result_metadata(fetch->handle);
fetch->column_count= mysql_num_fields(metadata);
mysql_free_result(metadata);
/*
Now allocate bind handles and buffers for output data:
calloc memory to reduce number of MYSQL_BIND members we need to
set up.
*/
fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) *
fetch->column_count);
fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count);
fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) *
fetch->column_count);
for (i= 0; i < fetch->column_count; ++i)
{
fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH);
fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING;
fetch->bind_array[i].buffer= fetch->out_data[i];
fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH;
fetch->bind_array[i].length= fetch->out_data_length + i;
}
mysql_stmt_bind_result(fetch->handle, fetch->bind_array);
fetch->row_count= 0;
fetch->is_open= TRUE;
/* Ready for reading rows */
DBUG_VOID_RETURN;
}
/* Fetch and print one row from cursor */
int stmt_fetch_fetch_row(Stmt_fetch *fetch)
{
int rc;
unsigned i;
DBUG_ENTER("stmt_fetch_fetch_row");
if ((rc= mysql_stmt_fetch(fetch->handle)) == 0)
{
++fetch->row_count;
if (!opt_silent)
printf("Stmt %d fetched row %d:\n", fetch->stmt_no, fetch->row_count);
for (i= 0; i < fetch->column_count; ++i)
{
fetch->out_data[i][fetch->out_data_length[i]]= '\0';
if (!opt_silent)
printf("column %d: %s\n", i+1, fetch->out_data[i]);
}
}
else
fetch->is_open= FALSE;
DBUG_RETURN(rc);
}
void stmt_fetch_close(Stmt_fetch *fetch)
{
unsigned i;
DBUG_ENTER("stmt_fetch_close");
for (i= 0; i < fetch->column_count; ++i)
free(fetch->out_data[i]);
free(fetch->out_data);
free(fetch->out_data_length);
free(fetch->bind_array);
mysql_stmt_close(fetch->handle);
DBUG_VOID_RETURN;
}
/*
For given array of queries, open query_count cursors and fetch
from them in simultaneous manner.
In case there was an error in one of the cursors, continue
reading from the rest.
*/
enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 };
my_bool fetch_n(const char **query_list, unsigned query_count,
enum fetch_type fetch_type)
{
unsigned open_statements= query_count;
int rc, error_count= 0;
Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) *
query_count);
Stmt_fetch *fetch;
DBUG_ENTER("fetch_n");
for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
{
/* Init will exit(1) in case of error */
stmt_fetch_init(fetch, fetch - fetch_array,
query_list[fetch - fetch_array]);
}
if (fetch_type == USE_STORE_RESULT)
{
for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
{
rc= mysql_stmt_store_result(fetch->handle);
check_execute(fetch->handle, rc);
}
}
while (open_statements)
{
for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
{
if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch)))
{
open_statements--;
/*
We try to fetch from the rest of the statements in case of
error
*/
if (rc != MYSQL_NO_DATA)
{
fprintf(stderr,
"Got error reading rows from statement %d,\n"
"query is: %s,\n"
"error message: %s", (int) (fetch - fetch_array),
fetch->query,
mysql_stmt_error(fetch->handle));
error_count++;
}
}
}
}
if (error_count)
fprintf(stderr, "Fetch FAILED");
else
{
unsigned total_row_count= 0;
for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
total_row_count+= fetch->row_count;
if (!opt_silent)
printf("Success, total rows fetched: %d\n", total_row_count);
}
for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch)
stmt_fetch_close(fetch);
free(fetch_array);
DBUG_RETURN(error_count != 0);
}
/* Separate thread query to test some cases */
static my_bool thread_query(const char *query)
{
MYSQL *l_mysql;
my_bool error;
error= 0;
if (!opt_silent)
fprintf(stdout, "\n in thread_query(%s)", query);
if (!(l_mysql= mysql_client_init(NULL)))
{
myerror("mysql_client_init() failed");
return 1;
}
if (!(mysql_real_connect(l_mysql, opt_host, opt_user,
opt_password, current_db, opt_port,
opt_unix_socket, 0)))
{
myerror("connection failed");
error= 1;
goto end;
}
l_mysql->reconnect= 1;
if (mysql_query(l_mysql, query))
{
fprintf(stderr, "Query failed (%s)\n", mysql_error(l_mysql));
error= 1;
goto end;
}
mysql_commit(l_mysql);
end:
mysql_close(l_mysql);
return error;
}
/* Query processing */
static void test_debug_example()
......@@ -19772,91 +18645,6 @@ static void test_bug13001491()
}
/*
Read and parse arguments and MySQL options from my.cnf
*/
static const char *client_test_load_default_groups[]= { "client", 0 };
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},
#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},
#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},
#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},
#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},
{"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("\
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);
}
static struct my_tests_st my_tests[]= {
{ "disable_query_logs", disable_query_logs },
{ "test_view_sp_list_fields", test_view_sp_list_fields },
......@@ -20123,183 +18911,4 @@ static struct my_tests_st my_tests[]= {
};
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
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);
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;
printf("All possible test names:\n\n");
for (fptr= my_tests; 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;
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;
}
/*
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");
}
}
/***************************************************************************
main routine
***************************************************************************/
int main(int argc, char **argv)
{
struct my_tests_st *fptr;
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_tests; fptr->name; fptr++)
(*fptr->function)();
}
else
{
for ( ; *argv ; argv++)
{
for (fptr= my_tests; 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]);
mysql_server_end();
my_end(0);
exit(0);
}
static struct my_tests_st *get_my_tests() { return my_tests; }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment