2005-11-30 01:02:21 +01:00
|
|
|
/* 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
|
2006-12-27 02:23:51 +01:00
|
|
|
the Free Software Foundation; version 2 of the License.
|
2005-11-30 01:02:21 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2005-12-25 00:41:40 +01:00
|
|
|
original idea: Brian Aker via playing with ab for too many years
|
2005-11-30 01:02:21 +01:00
|
|
|
coded by: Patrick Galbraith
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
MySQL Slap
|
|
|
|
|
|
|
|
A simple program designed to work as if multiple clients querying the database,
|
|
|
|
then reporting the timing of each stage.
|
|
|
|
|
|
|
|
MySQL slap runs three stages:
|
2006-01-02 05:08:45 +01:00
|
|
|
1) Create schema,table, and optionally any SP or data you want to beign
|
|
|
|
the test with. (single client)
|
2006-01-02 01:40:02 +01:00
|
|
|
2) Load test (many clients)
|
|
|
|
3) Cleanup (disconnection, drop table if specified, single client)
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2005-12-03 07:07:11 +01:00
|
|
|
Examples:
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2006-01-02 05:08:45 +01:00
|
|
|
Supply your own create and query SQL statements, with 50 clients
|
|
|
|
querying (200 selects for each):
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
mysqlslap --create="CREATE TABLE A (a int);INSERT INTO A (23)" \
|
|
|
|
--query="SELECT * FROM A" --concurrency=50 --iterations=200
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2005-12-03 07:07:11 +01:00
|
|
|
Let the program build the query SQL statement with a table of two int
|
|
|
|
columns, three varchar columns, five clients querying (20 times each),
|
|
|
|
don't create the table or insert the data (using the previous test's
|
|
|
|
schema and data):
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2005-12-03 07:07:11 +01:00
|
|
|
mysqlslap --concurrency=5 --iterations=20 \
|
|
|
|
--number-int-cols=2 --number-char-cols=3 \
|
2006-01-02 01:40:02 +01:00
|
|
|
--auto-generate-sql
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2005-12-03 07:07:11 +01:00
|
|
|
Tell the program to load the create, insert and query SQL statements from
|
|
|
|
the specified files, where the create.sql file has multiple table creation
|
2006-01-02 05:08:45 +01:00
|
|
|
statements delimited by ';' and multiple insert statements delimited by ';'.
|
|
|
|
The --query file will have multiple queries delimited by ';', run all the
|
|
|
|
load statements, and then run all the queries in the query file
|
2005-12-03 07:07:11 +01:00
|
|
|
with five clients (five times each):
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2006-02-14 04:09:10 +01:00
|
|
|
mysqlslap --concurrency=5 \
|
2005-12-03 07:07:11 +01:00
|
|
|
--iterations=5 --query=query.sql --create=create.sql \
|
2006-01-02 01:40:02 +01:00
|
|
|
--delimiter=";"
|
2005-12-25 00:41:40 +01:00
|
|
|
|
|
|
|
TODO:
|
|
|
|
Add language for better tests
|
|
|
|
String length for files and those put on the command line are not
|
2005-12-29 03:41:06 +01:00
|
|
|
setup to handle binary data.
|
|
|
|
Report results of each thread into the lock file we use.
|
2006-01-02 05:08:45 +01:00
|
|
|
More stats
|
|
|
|
Break up tests and run them on multiple hosts at once.
|
|
|
|
Allow output to be fed into a database directly.
|
2005-12-29 03:41:06 +01:00
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
*/
|
|
|
|
|
2005-12-29 03:41:06 +01:00
|
|
|
#define SHOW_VERSION "0.9"
|
2005-11-30 01:02:21 +01:00
|
|
|
|
|
|
|
#define HUGE_STRING_LENGTH 8096
|
|
|
|
#define RAND_STRING_SIZE 126
|
|
|
|
|
|
|
|
#include "client_priv.h"
|
2006-02-26 03:03:11 +01:00
|
|
|
#ifdef HAVE_LIBPTHREAD
|
2006-02-19 18:41:59 +01:00
|
|
|
#include <my_pthread.h>
|
2006-02-26 03:03:11 +01:00
|
|
|
#endif
|
2005-11-30 01:02:21 +01:00
|
|
|
#include <my_sys.h>
|
|
|
|
#include <m_string.h>
|
|
|
|
#include <mysql.h>
|
|
|
|
#include <mysqld_error.h>
|
|
|
|
#include <my_dir.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <sslopt-vars.h>
|
|
|
|
#include <sys/types.h>
|
2006-01-16 17:35:01 +01:00
|
|
|
#ifndef __WIN__
|
2005-11-30 01:02:21 +01:00
|
|
|
#include <sys/wait.h>
|
2006-01-16 17:35:01 +01:00
|
|
|
#endif
|
2005-12-25 00:41:40 +01:00
|
|
|
#include <ctype.h>
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2005-12-29 03:41:06 +01:00
|
|
|
#define MYSLAPLOCK "/myslaplock.lck"
|
|
|
|
#define MYSLAPLOCK_DIR "/tmp"
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2006-01-16 17:35:01 +01:00
|
|
|
#ifdef __WIN__
|
|
|
|
#define srandom srand
|
|
|
|
#define random rand
|
|
|
|
#define snprintf _snprintf
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SMEM
|
|
|
|
static char *shared_memory_base_name=0;
|
|
|
|
#endif
|
|
|
|
|
2005-12-03 07:07:11 +01:00
|
|
|
static char **defaults_argv;
|
2005-11-30 01:02:21 +01:00
|
|
|
|
|
|
|
static char *host= NULL, *opt_password= NULL, *user= NULL,
|
2006-01-02 01:40:02 +01:00
|
|
|
*user_supplied_query= NULL,
|
|
|
|
*default_engine= NULL,
|
2005-11-30 01:02:21 +01:00
|
|
|
*opt_mysql_unix_port= NULL;
|
|
|
|
|
2005-12-25 00:41:40 +01:00
|
|
|
const char *delimiter= "\n";
|
|
|
|
|
|
|
|
const char *create_schema_string= "mysqlslap";
|
|
|
|
|
2005-12-29 03:41:06 +01:00
|
|
|
const char *lock_directory;
|
|
|
|
char lock_file_str[FN_REFLEN];
|
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
static my_bool opt_preserve;
|
2005-12-25 00:41:40 +01:00
|
|
|
|
|
|
|
static my_bool opt_only_print= FALSE;
|
|
|
|
|
2005-12-29 03:41:06 +01:00
|
|
|
static my_bool opt_slave;
|
|
|
|
|
2005-12-03 07:07:11 +01:00
|
|
|
static my_bool opt_compress= FALSE, tty_password= FALSE,
|
2006-01-02 01:40:02 +01:00
|
|
|
opt_silent= FALSE,
|
2005-12-25 00:41:40 +01:00
|
|
|
auto_generate_sql= FALSE;
|
2007-01-29 22:17:30 +01:00
|
|
|
const char *auto_generate_sql_type= "mixed";
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2006-07-20 14:51:04 +02:00
|
|
|
static unsigned long connect_flags= CLIENT_MULTI_RESULTS;
|
|
|
|
|
2005-12-25 00:41:40 +01:00
|
|
|
static int verbose, num_int_cols, num_char_cols, delimiter_length;
|
2005-12-25 11:03:53 +01:00
|
|
|
static int iterations;
|
2005-11-30 01:02:21 +01:00
|
|
|
static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
|
2005-12-29 03:41:06 +01:00
|
|
|
static ulonglong actual_queries= 0;
|
|
|
|
static ulonglong num_of_query;
|
2007-01-29 22:17:30 +01:00
|
|
|
static ulonglong auto_generate_sql_number;
|
2005-12-25 11:03:53 +01:00
|
|
|
const char *concurrency_str= NULL;
|
2006-01-02 01:40:02 +01:00
|
|
|
static char *create_string;
|
2005-12-25 11:03:53 +01:00
|
|
|
uint *concurrency;
|
2005-11-30 01:02:21 +01:00
|
|
|
|
|
|
|
const char *default_dbug_option="d:t:o,/tmp/mysqlslap.trace";
|
2006-01-02 01:40:02 +01:00
|
|
|
const char *opt_csv_str;
|
|
|
|
File csv_file;
|
2005-11-30 01:02:21 +01:00
|
|
|
|
|
|
|
static uint opt_protocol= 0;
|
|
|
|
|
2005-12-03 07:07:11 +01:00
|
|
|
static int get_options(int *argc,char ***argv);
|
2005-11-30 01:02:21 +01:00
|
|
|
static uint opt_mysql_port= 0;
|
2006-01-12 06:30:52 +01:00
|
|
|
static uint opt_use_threads;
|
2005-11-30 01:02:21 +01:00
|
|
|
|
|
|
|
static const char *load_default_groups[]= { "mysqlslap","client",0 };
|
2005-12-03 07:07:11 +01:00
|
|
|
|
2005-12-25 00:41:40 +01:00
|
|
|
typedef struct statement statement;
|
|
|
|
|
|
|
|
struct statement {
|
|
|
|
char *string;
|
|
|
|
size_t length;
|
|
|
|
statement *next;
|
|
|
|
};
|
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
typedef struct stats stats;
|
|
|
|
|
|
|
|
struct stats {
|
|
|
|
long int timing;
|
|
|
|
uint users;
|
|
|
|
unsigned long long rows;
|
|
|
|
};
|
|
|
|
|
2006-01-12 06:30:52 +01:00
|
|
|
typedef struct thread_context thread_context;
|
|
|
|
|
|
|
|
struct thread_context {
|
|
|
|
statement *stmt;
|
|
|
|
ulonglong limit;
|
2006-02-19 18:41:59 +01:00
|
|
|
bool thread;
|
2006-01-12 06:30:52 +01:00
|
|
|
};
|
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
typedef struct conclusions conclusions;
|
|
|
|
|
|
|
|
struct conclusions {
|
|
|
|
char *engine;
|
|
|
|
long int avg_timing;
|
|
|
|
long int max_timing;
|
|
|
|
long int min_timing;
|
|
|
|
uint users;
|
|
|
|
unsigned long long avg_rows;
|
2006-01-02 05:27:24 +01:00
|
|
|
/* The following are not used yet */
|
2006-01-02 01:40:02 +01:00
|
|
|
unsigned long long max_rows;
|
|
|
|
unsigned long long min_rows;
|
|
|
|
};
|
|
|
|
|
2005-12-25 00:41:40 +01:00
|
|
|
static statement *create_statements= NULL,
|
2005-12-25 11:03:53 +01:00
|
|
|
*engine_statements= NULL,
|
2005-12-25 00:41:40 +01:00
|
|
|
*query_statements= NULL;
|
|
|
|
|
|
|
|
/* Prototypes */
|
2006-01-02 01:40:02 +01:00
|
|
|
void print_conclusions(conclusions *con);
|
|
|
|
void print_conclusions_csv(conclusions *con);
|
|
|
|
void generate_stats(conclusions *con, statement *eng, stats *sptr);
|
2005-12-25 11:03:53 +01:00
|
|
|
uint parse_comma(const char *string, uint **range);
|
|
|
|
uint parse_delimiter(const char *script, statement **stmt, char delm);
|
2005-12-25 00:41:40 +01:00
|
|
|
static int drop_schema(MYSQL *mysql, const char *db);
|
2005-12-29 03:41:06 +01:00
|
|
|
uint get_random_string(char *buf);
|
2006-01-02 01:40:02 +01:00
|
|
|
static statement *build_table_string(void);
|
|
|
|
static statement *build_insert_string(void);
|
|
|
|
static statement *build_query_string(void);
|
2005-12-25 11:03:53 +01:00
|
|
|
static int create_schema(MYSQL *mysql, const char *db, statement *stmt,
|
|
|
|
statement *engine_stmt);
|
2006-01-02 01:40:02 +01:00
|
|
|
static int run_scheduler(stats *sptr, statement *stmts, uint concur,
|
|
|
|
ulonglong limit);
|
2006-01-12 06:30:52 +01:00
|
|
|
int run_task(thread_context *con);
|
2006-01-02 05:08:45 +01:00
|
|
|
void statement_cleanup(statement *stmt);
|
2005-12-25 00:41:40 +01:00
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
static const char ALPHANUMERICS[]=
|
|
|
|
"0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
|
2005-12-25 00:41:40 +01:00
|
|
|
|
2005-12-03 07:07:11 +01:00
|
|
|
#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
|
2005-11-30 01:02:21 +01:00
|
|
|
|
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
static long int timedif(struct timeval a, struct timeval b)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-02 01:40:02 +01:00
|
|
|
register int us, s;
|
|
|
|
|
|
|
|
us = a.tv_usec - b.tv_usec;
|
|
|
|
us /= 1000;
|
|
|
|
s = a.tv_sec - b.tv_sec;
|
|
|
|
s *= 1000;
|
|
|
|
return s + us;
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
2006-01-16 17:35:01 +01:00
|
|
|
#ifdef __WIN__
|
|
|
|
static int gettimeofday(struct timeval *tp, void *tzp)
|
|
|
|
{
|
|
|
|
unsigned int ticks;
|
|
|
|
ticks= GetTickCount();
|
|
|
|
tp->tv_usec= ticks*1000;
|
|
|
|
tp->tv_sec= ticks/1000;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
2005-11-30 01:02:21 +01:00
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
MYSQL mysql;
|
2005-12-25 11:03:53 +01:00
|
|
|
int x;
|
2006-01-02 05:08:45 +01:00
|
|
|
unsigned long long client_limit;
|
|
|
|
statement *eptr;
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2006-01-20 16:20:03 +01:00
|
|
|
#ifdef __WIN__
|
|
|
|
opt_use_threads= 1;
|
|
|
|
#endif
|
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
MY_INIT(argv[0]);
|
|
|
|
|
|
|
|
load_defaults("my",load_default_groups,&argc,&argv);
|
2005-12-03 07:07:11 +01:00
|
|
|
defaults_argv=argv;
|
|
|
|
if (get_options(&argc,&argv))
|
|
|
|
{
|
|
|
|
free_defaults(defaults_argv);
|
|
|
|
my_end(0);
|
|
|
|
exit(1);
|
|
|
|
}
|
2006-03-29 03:59:11 +02:00
|
|
|
|
2006-04-11 22:04:08 +02:00
|
|
|
/* Seed the random number generator if we will be using it. */
|
|
|
|
if (auto_generate_sql)
|
|
|
|
srandom((uint)time(NULL));
|
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
/* globals? Yes, so we only have to run strlen once */
|
2005-12-25 00:41:40 +01:00
|
|
|
delimiter_length= strlen(delimiter);
|
2005-11-30 01:02:21 +01:00
|
|
|
|
|
|
|
if (argc > 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"%s: Too many arguments\n",my_progname);
|
2005-12-03 07:07:11 +01:00
|
|
|
free_defaults(defaults_argv);
|
|
|
|
my_end(0);
|
2005-11-30 01:02:21 +01:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
mysql_init(&mysql);
|
|
|
|
if (opt_compress)
|
|
|
|
mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
|
|
|
|
#ifdef HAVE_OPENSSL
|
|
|
|
if (opt_use_ssl)
|
|
|
|
mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
|
|
|
|
opt_ssl_capath, opt_ssl_cipher);
|
|
|
|
#endif
|
|
|
|
if (opt_protocol)
|
|
|
|
mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
|
|
|
|
#ifdef HAVE_SMEM
|
|
|
|
if (shared_memory_base_name)
|
|
|
|
mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
|
|
|
|
#endif
|
|
|
|
mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
|
|
|
|
|
2005-12-25 00:41:40 +01:00
|
|
|
if (!opt_only_print)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-03-10 17:54:12 +01:00
|
|
|
if (!(mysql_real_connect(&mysql, host, user, opt_password,
|
|
|
|
NULL, opt_mysql_port,
|
2006-07-20 14:51:04 +02:00
|
|
|
opt_mysql_unix_port, connect_flags)))
|
2005-12-25 00:41:40 +01:00
|
|
|
{
|
2006-04-11 22:04:08 +02:00
|
|
|
fprintf(stderr,"%s: Error when connecting to server: %s\n",
|
|
|
|
my_progname,mysql_error(&mysql));
|
2005-12-25 00:41:40 +01:00
|
|
|
free_defaults(defaults_argv);
|
|
|
|
my_end(0);
|
|
|
|
exit(1);
|
|
|
|
}
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
2006-01-02 05:27:24 +01:00
|
|
|
/* Main iterations loop */
|
2006-01-02 01:40:02 +01:00
|
|
|
eptr= engine_statements;
|
|
|
|
do
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-02 01:40:02 +01:00
|
|
|
/* For the final stage we run whatever queries we were asked to run */
|
|
|
|
uint *current;
|
|
|
|
conclusions conclusion;
|
2005-12-25 11:03:53 +01:00
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
for (current= concurrency; current && *current; current++)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-02 05:08:45 +01:00
|
|
|
stats *head_sptr;
|
|
|
|
stats *sptr;
|
|
|
|
|
2006-01-03 11:09:18 +01:00
|
|
|
head_sptr= (stats *)my_malloc(sizeof(stats) * iterations, MYF(MY_ZEROFILL));
|
2006-01-02 01:40:02 +01:00
|
|
|
|
|
|
|
bzero(&conclusion, sizeof(conclusions));
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
if (num_of_query)
|
|
|
|
client_limit= num_of_query / *current;
|
|
|
|
else
|
|
|
|
client_limit= actual_queries;
|
|
|
|
|
2006-01-03 11:09:18 +01:00
|
|
|
for (x= 0, sptr= head_sptr; x < iterations; x++, sptr++)
|
2005-12-25 11:03:53 +01:00
|
|
|
{
|
2006-01-02 01:40:02 +01:00
|
|
|
/*
|
|
|
|
We might not want to load any data, such as when we are calling
|
|
|
|
a stored_procedure that doesn't use data, or we know we already have
|
|
|
|
data in the table.
|
|
|
|
*/
|
|
|
|
if (!opt_preserve)
|
|
|
|
drop_schema(&mysql, create_schema_string);
|
|
|
|
/* First we create */
|
|
|
|
if (create_statements)
|
|
|
|
create_schema(&mysql, create_schema_string, create_statements, eptr);
|
|
|
|
|
|
|
|
run_scheduler(sptr, query_statements, *current, client_limit);
|
2005-12-25 11:03:53 +01:00
|
|
|
}
|
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
generate_stats(&conclusion, eptr, head_sptr);
|
2005-12-25 11:03:53 +01:00
|
|
|
|
|
|
|
if (!opt_silent)
|
2006-01-02 01:40:02 +01:00
|
|
|
print_conclusions(&conclusion);
|
|
|
|
if (opt_csv_str)
|
|
|
|
print_conclusions_csv(&conclusion);
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2006-01-02 05:08:45 +01:00
|
|
|
my_free((byte *)head_sptr, MYF(0));
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
2006-01-02 01:40:02 +01:00
|
|
|
|
|
|
|
if (!opt_preserve)
|
|
|
|
drop_schema(&mysql, create_schema_string);
|
|
|
|
} while (eptr ? (eptr= eptr->next) : 0);
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2005-12-25 00:41:40 +01:00
|
|
|
if (!opt_only_print)
|
|
|
|
mysql_close(&mysql); /* Close & free connection */
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2005-12-29 03:41:06 +01:00
|
|
|
|
|
|
|
/* Remove lock file */
|
|
|
|
my_delete(lock_file_str, MYF(0));
|
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
/* now free all the strings we created */
|
|
|
|
if (opt_password)
|
2005-12-25 00:41:40 +01:00
|
|
|
my_free(opt_password, MYF(0));
|
|
|
|
|
2005-12-25 11:03:53 +01:00
|
|
|
my_free((byte *)concurrency, MYF(0));
|
|
|
|
|
2006-01-02 05:08:45 +01:00
|
|
|
statement_cleanup(create_statements);
|
|
|
|
statement_cleanup(engine_statements);
|
|
|
|
statement_cleanup(query_statements);
|
2005-12-25 00:41:40 +01:00
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
#ifdef HAVE_SMEM
|
|
|
|
if (shared_memory_base_name)
|
|
|
|
my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
|
|
|
|
#endif
|
2005-12-03 07:07:11 +01:00
|
|
|
free_defaults(defaults_argv);
|
2005-11-30 01:02:21 +01:00
|
|
|
my_end(0);
|
|
|
|
|
2006-01-16 17:35:01 +01:00
|
|
|
return 0;
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
2005-12-25 11:03:53 +01:00
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
static struct my_option my_long_options[] =
|
|
|
|
{
|
2006-01-19 03:27:07 +01:00
|
|
|
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
|
|
|
|
0, 0, 0, 0, 0, 0},
|
2005-12-03 07:07:11 +01:00
|
|
|
{"auto-generate-sql", 'a',
|
|
|
|
"Generate SQL where not supplied by file or command line.",
|
2005-11-30 01:02:21 +01:00
|
|
|
(gptr*) &auto_generate_sql, (gptr*) &auto_generate_sql,
|
|
|
|
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
2007-01-29 22:17:30 +01:00
|
|
|
{"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE,
|
|
|
|
"Load types are mixed, write, or read. Default is mixed\n",
|
|
|
|
(gptr*) &auto_generate_sql_type, (gptr*) &auto_generate_sql_type,
|
|
|
|
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
2007-02-05 00:31:35 +01:00
|
|
|
{"auto-generate-sql-write-number", OPT_SLAP_AUTO_GENERATE_WRITE_NUM,
|
2007-01-29 22:17:30 +01:00
|
|
|
"Number of rows to insert to used in read and write loads (default is 100).\n",
|
|
|
|
(gptr*) &auto_generate_sql_number, (gptr*) &auto_generate_sql_number,
|
|
|
|
0, GET_ULL, REQUIRED_ARG, 100, 0, 0, 0, 0, 0},
|
2005-11-30 01:02:21 +01:00
|
|
|
{"compress", 'C', "Use compression in server/client protocol.",
|
|
|
|
(gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
|
|
|
|
0, 0, 0},
|
|
|
|
{"concurrency", 'c', "Number of clients to simulate for query to run.",
|
2005-12-25 11:03:53 +01:00
|
|
|
(gptr*) &concurrency_str, (gptr*) &concurrency_str, 0, GET_STR,
|
|
|
|
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
2007-01-29 22:17:30 +01:00
|
|
|
{"create", OPT_SLAP_CREATE_STRING, "File or string to use create tables.",
|
2005-11-30 01:02:21 +01:00
|
|
|
(gptr*) &create_string, (gptr*) &create_string, 0, GET_STR, REQUIRED_ARG,
|
|
|
|
0, 0, 0, 0, 0, 0},
|
2005-12-25 00:41:40 +01:00
|
|
|
{"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.",
|
|
|
|
(gptr*) &create_schema_string, (gptr*) &create_schema_string, 0, GET_STR,
|
|
|
|
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
2007-01-29 22:17:30 +01:00
|
|
|
{"csv", OPT_SLAP_CSV,
|
2006-01-19 19:33:51 +01:00
|
|
|
"Generate CSV output to named file or to stdout if no file is named.",
|
2006-01-02 01:40:02 +01:00
|
|
|
(gptr*) &opt_csv_str, (gptr*) &opt_csv_str, 0, GET_STR,
|
|
|
|
OPT_ARG, 0, 0, 0, 0, 0, 0},
|
2005-11-30 01:02:21 +01:00
|
|
|
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
|
|
|
|
(gptr*) &default_dbug_option, (gptr*) &default_dbug_option, 0, GET_STR,
|
|
|
|
OPT_ARG, 0, 0, 0, 0, 0, 0},
|
2005-12-03 07:07:11 +01:00
|
|
|
{"delimiter", 'F',
|
|
|
|
"Delimiter to use in SQL statements supplied in file or command line.",
|
2005-11-30 01:02:21 +01:00
|
|
|
(gptr*) &delimiter, (gptr*) &delimiter, 0, GET_STR, REQUIRED_ARG,
|
|
|
|
0, 0, 0, 0, 0, 0},
|
|
|
|
{"engine", 'e', "Storage engine to use for creating the table.",
|
|
|
|
(gptr*) &default_engine, (gptr*) &default_engine, 0,
|
|
|
|
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
|
|
{"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR,
|
|
|
|
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
2005-12-25 11:03:53 +01:00
|
|
|
{"iterations", 'i', "Number of times too run the tests.", (gptr*) &iterations,
|
|
|
|
(gptr*) &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0},
|
2006-01-02 01:40:02 +01:00
|
|
|
{"lock-directory", OPT_MYSQL_LOCK_DIRECTORY, "Directory to use to keep locks.",
|
2005-12-29 03:41:06 +01:00
|
|
|
(gptr*) &lock_directory, (gptr*) &lock_directory, 0, GET_STR,
|
|
|
|
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
2005-12-25 00:41:40 +01:00
|
|
|
{"number-char-cols", 'x',
|
2007-02-05 00:31:35 +01:00
|
|
|
"Number of VARCHAR columns to create table with if specifying --auto-generate-sql ",
|
2005-11-30 01:02:21 +01:00
|
|
|
(gptr*) &num_char_cols, (gptr*) &num_char_cols, 0, GET_UINT, REQUIRED_ARG,
|
2006-01-02 01:40:02 +01:00
|
|
|
1, 0, 0, 0, 0, 0},
|
2005-12-25 00:41:40 +01:00
|
|
|
{"number-int-cols", 'y',
|
2007-02-05 00:31:35 +01:00
|
|
|
"Number of INT columns to create table with if specifying --auto-generate-sql.",
|
|
|
|
(gptr*) &num_int_cols, (gptr*) &num_int_cols, 0, GET_UINT, REQUIRED_ARG,
|
|
|
|
1, 0, 0, 0, 0, 0},
|
2006-01-19 03:27:07 +01:00
|
|
|
{"number-of-queries", OPT_MYSQL_NUMBER_OF_QUERY,
|
2005-12-29 03:41:06 +01:00
|
|
|
"Limit each client to this number of queries (this is not exact).",
|
|
|
|
(gptr*) &num_of_query, (gptr*) &num_of_query, 0,
|
|
|
|
GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
2005-12-25 00:41:40 +01:00
|
|
|
{"only-print", OPT_MYSQL_ONLY_PRINT,
|
2006-01-19 03:27:07 +01:00
|
|
|
"This causes mysqlslap to not connect to the databases, but instead print "
|
|
|
|
"out what it would have done instead.",
|
2005-12-25 00:41:40 +01:00
|
|
|
(gptr*) &opt_only_print, (gptr*) &opt_only_print, 0, GET_BOOL, NO_ARG,
|
2005-11-30 01:02:21 +01:00
|
|
|
0, 0, 0, 0, 0, 0},
|
|
|
|
{"password", 'p',
|
2006-01-19 03:27:07 +01:00
|
|
|
"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},
|
2005-11-30 01:02:21 +01:00
|
|
|
#ifdef __WIN__
|
|
|
|
{"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
|
|
|
|
NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
|
|
#endif
|
2006-01-19 03:27:07 +01:00
|
|
|
{"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port,
|
|
|
|
(gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
|
|
|
|
0},
|
2006-01-02 01:40:02 +01:00
|
|
|
{"preserve-schema", OPT_MYSQL_PRESERVE_SCHEMA,
|
2006-04-28 17:44:08 +02:00
|
|
|
"Preserve the schema from the mysqlslap run, this happens unless "
|
|
|
|
"--auto-generate-sql or --create are used.",
|
2006-01-02 01:40:02 +01:00
|
|
|
(gptr*) &opt_preserve, (gptr*) &opt_preserve, 0, GET_BOOL,
|
2006-03-29 03:59:11 +02:00
|
|
|
NO_ARG, TRUE, 0, 0, 0, 0, 0},
|
2005-11-30 01:02:21 +01:00
|
|
|
{"protocol", OPT_MYSQL_PROTOCOL,
|
|
|
|
"The protocol of connection (tcp,socket,pipe,memory).",
|
|
|
|
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
2005-12-29 03:41:06 +01:00
|
|
|
{"query", 'q', "Query to run or file containing query to run.",
|
|
|
|
(gptr*) &user_supplied_query, (gptr*) &user_supplied_query,
|
|
|
|
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
2005-11-30 01:02:21 +01:00
|
|
|
#ifdef HAVE_SMEM
|
|
|
|
{"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
|
|
|
|
"Base name of shared memory.", (gptr*) &shared_memory_base_name,
|
|
|
|
(gptr*) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG,
|
|
|
|
0, 0, 0, 0, 0, 0},
|
|
|
|
#endif
|
2006-01-19 03:27:07 +01:00
|
|
|
{"silent", 's', "Run program in silent mode - no output.",
|
|
|
|
(gptr*) &opt_silent, (gptr*) &opt_silent, 0, GET_BOOL, NO_ARG,
|
|
|
|
0, 0, 0, 0, 0, 0},
|
2005-12-29 03:41:06 +01:00
|
|
|
{"slave", OPT_MYSQL_SLAP_SLAVE, "Follow master locks for other slap clients",
|
|
|
|
(gptr*) &opt_slave, (gptr*) &opt_slave, 0, GET_BOOL, NO_ARG,
|
|
|
|
0, 0, 0, 0, 0, 0},
|
2005-11-30 01:02:21 +01:00
|
|
|
{"socket", 'S', "Socket file to use for connection.",
|
|
|
|
(gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR,
|
|
|
|
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
2006-01-19 03:27:07 +01:00
|
|
|
#include <sslopt-longopts.h>
|
2006-01-12 06:30:52 +01:00
|
|
|
{"use-threads", OPT_USE_THREADS,
|
|
|
|
"Use pthread calls instead of fork() calls (default on Windows)",
|
|
|
|
(gptr*) &opt_use_threads, (gptr*) &opt_use_threads, 0,
|
|
|
|
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
|
2005-11-30 01:02:21 +01:00
|
|
|
#ifndef DONT_ALLOW_USER_CHANGE
|
|
|
|
{"user", 'u', "User for login if not current user.", (gptr*) &user,
|
|
|
|
(gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
|
|
|
#endif
|
|
|
|
{"verbose", 'v',
|
2006-01-19 03:27:07 +01:00
|
|
|
"More verbose output; You can use this multiple times to get even more "
|
|
|
|
"verbose output.", (gptr*) &verbose, (gptr*) &verbose, 0,
|
2005-12-25 00:41:40 +01:00
|
|
|
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
|
2005-11-30 01:02:21 +01:00
|
|
|
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
|
|
|
|
NO_ARG, 0, 0, 0, 0, 0, 0},
|
|
|
|
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#include <help_start.h>
|
|
|
|
|
|
|
|
static void print_version(void)
|
|
|
|
{
|
|
|
|
printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,SHOW_VERSION,
|
|
|
|
MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void usage(void)
|
|
|
|
{
|
|
|
|
print_version();
|
|
|
|
puts("Copyright (C) 2005 MySQL AB");
|
|
|
|
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\
|
|
|
|
\nand you are welcome to modify and redistribute it under the GPL \
|
|
|
|
license\n");
|
|
|
|
puts("Run a query multiple times against the server\n");
|
2005-12-03 07:07:11 +01:00
|
|
|
printf("Usage: %s [OPTIONS]\n",my_progname);
|
2005-11-30 01:02:21 +01:00
|
|
|
print_defaults("my",load_default_groups);
|
|
|
|
my_print_help(my_long_options);
|
|
|
|
}
|
|
|
|
|
|
|
|
#include <help_end.h>
|
|
|
|
|
|
|
|
static my_bool
|
|
|
|
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
|
|
|
char *argument)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("get_one_option");
|
|
|
|
switch(optid) {
|
|
|
|
#ifdef __NETWARE__
|
|
|
|
case OPT_AUTO_CLOSE:
|
|
|
|
setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case 'v':
|
|
|
|
verbose++;
|
|
|
|
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; /* Cut length of argument */
|
|
|
|
tty_password= 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
tty_password= 1;
|
|
|
|
break;
|
|
|
|
case 'W':
|
|
|
|
#ifdef __WIN__
|
|
|
|
opt_protocol= MYSQL_PROTOCOL_PIPE;
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case OPT_MYSQL_PROTOCOL:
|
|
|
|
{
|
|
|
|
if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Unknown option to protocol: %s\n", argument);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '#':
|
|
|
|
DBUG_PUSH(argument ? argument : default_dbug_option);
|
|
|
|
break;
|
|
|
|
#include <sslopt-case.h>
|
|
|
|
case 'V':
|
|
|
|
print_version();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
case 'I': /* Info */
|
|
|
|
usage();
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-29 03:41:06 +01:00
|
|
|
uint
|
2005-11-30 01:02:21 +01:00
|
|
|
get_random_string(char *buf)
|
|
|
|
{
|
|
|
|
char *buf_ptr= buf;
|
2005-12-03 07:07:11 +01:00
|
|
|
int x;
|
2005-11-30 01:02:21 +01:00
|
|
|
DBUG_ENTER("get_random_string");
|
|
|
|
for (x= RAND_STRING_SIZE; x > 0; x--)
|
2005-12-03 07:07:11 +01:00
|
|
|
*buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
|
|
|
|
DBUG_RETURN(buf_ptr - buf);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
build_table_string
|
|
|
|
|
|
|
|
This function builds a create table query if the user opts to not supply
|
|
|
|
a file or string containing a create table statement
|
|
|
|
*/
|
2006-01-02 01:40:02 +01:00
|
|
|
static statement *
|
2005-11-30 01:02:21 +01:00
|
|
|
build_table_string(void)
|
|
|
|
{
|
|
|
|
char buf[512];
|
|
|
|
int col_count;
|
2006-01-02 01:40:02 +01:00
|
|
|
statement *ptr;
|
2005-11-30 01:02:21 +01:00
|
|
|
DYNAMIC_STRING table_string;
|
|
|
|
DBUG_ENTER("build_table_string");
|
|
|
|
|
|
|
|
DBUG_PRINT("info", ("num int cols %d num char cols %d",
|
|
|
|
num_int_cols, num_char_cols));
|
|
|
|
|
|
|
|
init_dynamic_string(&table_string, "", 1024, 1024);
|
|
|
|
|
2005-12-25 00:41:40 +01:00
|
|
|
dynstr_append(&table_string, "CREATE TABLE `t1` (");
|
2005-11-30 01:02:21 +01:00
|
|
|
for (col_count= 1; col_count <= num_int_cols; col_count++)
|
|
|
|
{
|
|
|
|
sprintf(buf, "intcol%d INT(32)", col_count);
|
|
|
|
dynstr_append(&table_string, buf);
|
|
|
|
|
|
|
|
if (col_count < num_int_cols || num_char_cols > 0)
|
2005-12-25 00:41:40 +01:00
|
|
|
dynstr_append(&table_string, ",");
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
for (col_count= 1; col_count <= num_char_cols; col_count++)
|
|
|
|
{
|
|
|
|
sprintf(buf, "charcol%d VARCHAR(128)", col_count);
|
|
|
|
dynstr_append(&table_string, buf);
|
|
|
|
|
|
|
|
if (col_count < num_char_cols)
|
2005-12-25 00:41:40 +01:00
|
|
|
dynstr_append(&table_string, ",");
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
2005-12-25 00:41:40 +01:00
|
|
|
dynstr_append(&table_string, ")");
|
2006-01-02 01:40:02 +01:00
|
|
|
ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL));
|
|
|
|
ptr->string = (char *)my_malloc(table_string.length+1, MYF(MY_WME));
|
|
|
|
ptr->length= table_string.length+1;
|
|
|
|
strmov(ptr->string, table_string.str);
|
2005-11-30 01:02:21 +01:00
|
|
|
dynstr_free(&table_string);
|
2006-01-02 01:40:02 +01:00
|
|
|
DBUG_RETURN(ptr);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
2005-12-25 11:03:53 +01:00
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
/*
|
|
|
|
build_insert_string()
|
|
|
|
|
|
|
|
This function builds insert statements when the user opts to not supply
|
2005-12-25 00:41:40 +01:00
|
|
|
an insert file or string containing insert data
|
2005-11-30 01:02:21 +01:00
|
|
|
*/
|
2006-01-02 01:40:02 +01:00
|
|
|
static statement *
|
2005-11-30 01:02:21 +01:00
|
|
|
build_insert_string(void)
|
|
|
|
{
|
|
|
|
char buf[RAND_STRING_SIZE];
|
|
|
|
int col_count;
|
2006-01-02 01:40:02 +01:00
|
|
|
statement *ptr;
|
2005-11-30 01:02:21 +01:00
|
|
|
DYNAMIC_STRING insert_string;
|
|
|
|
DBUG_ENTER("build_insert_string");
|
|
|
|
|
|
|
|
init_dynamic_string(&insert_string, "", 1024, 1024);
|
|
|
|
|
|
|
|
dynstr_append_mem(&insert_string, "INSERT INTO t1 VALUES (", 23);
|
|
|
|
for (col_count= 1; col_count <= num_int_cols; col_count++)
|
|
|
|
{
|
2005-12-03 07:07:11 +01:00
|
|
|
sprintf(buf, "%ld", random());
|
2005-11-30 01:02:21 +01:00
|
|
|
dynstr_append(&insert_string, buf);
|
|
|
|
|
|
|
|
if (col_count < num_int_cols || num_char_cols > 0)
|
|
|
|
dynstr_append_mem(&insert_string, ",", 1);
|
|
|
|
}
|
|
|
|
for (col_count= 1; col_count <= num_char_cols; col_count++)
|
|
|
|
{
|
2005-12-03 07:07:11 +01:00
|
|
|
int buf_len= get_random_string(buf);
|
2005-11-30 01:02:21 +01:00
|
|
|
dynstr_append_mem(&insert_string, "'", 1);
|
2005-12-03 07:07:11 +01:00
|
|
|
dynstr_append_mem(&insert_string, buf, buf_len);
|
2005-11-30 01:02:21 +01:00
|
|
|
dynstr_append_mem(&insert_string, "'", 1);
|
|
|
|
|
|
|
|
if (col_count < num_char_cols)
|
|
|
|
dynstr_append_mem(&insert_string, ",", 1);
|
|
|
|
}
|
|
|
|
dynstr_append_mem(&insert_string, ")", 1);
|
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL));
|
|
|
|
ptr->string= (char *)my_malloc(insert_string.length+1, MYF(MY_WME));
|
|
|
|
ptr->length= insert_string.length+1;
|
|
|
|
strmov(ptr->string, insert_string.str);
|
2005-11-30 01:02:21 +01:00
|
|
|
dynstr_free(&insert_string);
|
2006-01-02 01:40:02 +01:00
|
|
|
DBUG_RETURN(ptr);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
2005-12-25 11:03:53 +01:00
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
/*
|
|
|
|
build_query_string()
|
|
|
|
|
|
|
|
This function builds a query if the user opts to not supply a query
|
|
|
|
statement or file containing a query statement
|
|
|
|
*/
|
2006-01-02 01:40:02 +01:00
|
|
|
static statement *
|
2005-11-30 01:02:21 +01:00
|
|
|
build_query_string(void)
|
|
|
|
{
|
|
|
|
char buf[512];
|
|
|
|
int col_count;
|
2006-01-02 01:40:02 +01:00
|
|
|
statement *ptr;
|
2005-11-30 01:02:21 +01:00
|
|
|
static DYNAMIC_STRING query_string;
|
|
|
|
DBUG_ENTER("build_query_string");
|
|
|
|
|
|
|
|
init_dynamic_string(&query_string, "", 1024, 1024);
|
|
|
|
|
|
|
|
dynstr_append_mem(&query_string, "SELECT ", 7);
|
|
|
|
for (col_count= 1; col_count <= num_int_cols; col_count++)
|
|
|
|
{
|
|
|
|
sprintf(buf, "intcol%d", col_count);
|
|
|
|
dynstr_append(&query_string, buf);
|
|
|
|
|
|
|
|
if (col_count < num_int_cols || num_char_cols > 0)
|
|
|
|
dynstr_append_mem(&query_string, ",", 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
for (col_count= 1; col_count <= num_char_cols; col_count++)
|
|
|
|
{
|
|
|
|
sprintf(buf, "charcol%d", col_count);
|
|
|
|
dynstr_append(&query_string, buf);
|
|
|
|
|
|
|
|
if (col_count < num_char_cols)
|
|
|
|
dynstr_append_mem(&query_string, ",", 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
dynstr_append_mem(&query_string, " FROM t1", 8);
|
2006-01-02 01:40:02 +01:00
|
|
|
ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL));
|
|
|
|
ptr->string= (char *)my_malloc(query_string.length+1, MYF(MY_WME));
|
|
|
|
ptr->length= query_string.length+1;
|
|
|
|
strmov(ptr->string, query_string.str);
|
2005-11-30 01:02:21 +01:00
|
|
|
dynstr_free(&query_string);
|
dbug changes:
1. dbug state is now local to a thread
2. new macros: DBUG_EXPLAIN, DBUG_EXPLAIN_INITIAL,
DBUG_SET, DBUG_SET_INITIAL, DBUG_EVALUATE, DBUG_EVALUATE_IF
3. macros are do{}while(0) wrapped
4. incremental modifications to the dbug state (e.g. "+d,info:-t")
5. dbug code cleanup, style fixes
6. _db_on_ and DEBUGGER_ON/OFF removed
7. rest of MySQL code fixed because of 3 (missing ;) and 6
8. dbug manual updated
9. server variable @@debug (global and local) to control dbug from SQL!
a. -#T to print timestamps in the log
BitKeeper/deleted/.del-readme.prof~2f3bae1550a0038d:
Delete: dbug/readme.prof
client/mysqlslap.c:
typo fixed
configure.in:
test for sleep() too
dbug/dbug.c:
thread local dbug settings
DBUG_EXPLAIN,DBUG_EXPLAIN_INITIAL,DBUG_SET,DBUG_SET_INITIAL
style changes to be more in line with MySQL code
cleanup (many mallocs removed)
incremental modification of dbug state (e.g. DBUG_PUSH("+t:-d,info"))
DBUG_SET, _db_explain_
-#T
dbug/monty.doc:
obsolete and duplicate docs removed
dbug/user.r:
new features documented
include/my_dbug.h:
correct do{}while wrapping
thread local dbug settings
DBUG_EXPLAIN,DBUG_EXPLAIN_INITIAL,DBUG_SET,DBUG_SET_INITIAL
DBUG_EVALUATE,DBUG_EVALUATE_IF
libmysql/libmysql.c:
remove _db_on_ and DEBUGGER_ON/OFF
mysys/my_init.c:
missed DBUG_RETURN
mysys/my_thr_init.c:
bugfix - transaction id's are unsigned
mysys/testhash.c:
remove _db_on_ and DEBUGGER_ON/OFF
sql/ha_myisammrg.cc:
missed ;
sql/ha_ndbcluster.cc:
remove _db_on_ and DEBUGGER_ON/OFF
missed ;
sql/ha_ndbcluster_binlog.cc:
remove _db_on_ and DEBUGGER_ON/OFF
missed ;
sql/item_cmpfunc.cc:
missed ;
sql/lock.cc:
missed DBUG_RETURN
sql/log_event.cc:
missed ;
sql/mysqld.cc:
remove _db_on_ and DEBUGGER_ON/OFF
missed ;
DBUG_SET_INITIAL
sql/opt_range.cc:
remove _db_on_ and DEBUGGER_ON/OFF
sql/set_var.cc:
class sys_var_thd_dbug and "debug" server variable
sql/set_var.h:
class sys_var_thd_dbug and "debug" server variable
sql/slave.cc:
missed ;
sql/sql_cache.cc:
missed ;
sql/sql_plugin.cc:
missed ;
sql/sql_select.cc:
remove _db_on_ and DEBUGGER_ON/OFF
storage/heap/hp_test2.c:
remove _db_on_ and DEBUGGER_ON/OFF
storage/myisam/ft_eval.c:
remove _db_on_ and DEBUGGER_ON/OFF
storage/myisam/ft_test1.c:
remove _db_on_ and DEBUGGER_ON/OFF
storage/myisam/mi_open.c:
remove _db_on_ and DEBUGGER_ON/OFF
missed ;
storage/myisam/mi_test1.c:
remove _db_on_ and DEBUGGER_ON/OFF
storage/myisam/mi_test2.c:
remove _db_on_ and DEBUGGER_ON/OFF
storage/myisam/mi_test3.c:
remove _db_on_ and DEBUGGER_ON/OFF
storage/ndb/src/ndbapi/DictCache.cpp:
missed ;
storage/ndb/src/ndbapi/NdbTransaction.cpp:
missed ;
tests/mysql_client_test.c:
remove _db_on_ and DEBUGGER_ON/OFF
2006-02-14 22:36:11 +01:00
|
|
|
DBUG_RETURN(ptr);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
dbug changes:
1. dbug state is now local to a thread
2. new macros: DBUG_EXPLAIN, DBUG_EXPLAIN_INITIAL,
DBUG_SET, DBUG_SET_INITIAL, DBUG_EVALUATE, DBUG_EVALUATE_IF
3. macros are do{}while(0) wrapped
4. incremental modifications to the dbug state (e.g. "+d,info:-t")
5. dbug code cleanup, style fixes
6. _db_on_ and DEBUGGER_ON/OFF removed
7. rest of MySQL code fixed because of 3 (missing ;) and 6
8. dbug manual updated
9. server variable @@debug (global and local) to control dbug from SQL!
a. -#T to print timestamps in the log
BitKeeper/deleted/.del-readme.prof~2f3bae1550a0038d:
Delete: dbug/readme.prof
client/mysqlslap.c:
typo fixed
configure.in:
test for sleep() too
dbug/dbug.c:
thread local dbug settings
DBUG_EXPLAIN,DBUG_EXPLAIN_INITIAL,DBUG_SET,DBUG_SET_INITIAL
style changes to be more in line with MySQL code
cleanup (many mallocs removed)
incremental modification of dbug state (e.g. DBUG_PUSH("+t:-d,info"))
DBUG_SET, _db_explain_
-#T
dbug/monty.doc:
obsolete and duplicate docs removed
dbug/user.r:
new features documented
include/my_dbug.h:
correct do{}while wrapping
thread local dbug settings
DBUG_EXPLAIN,DBUG_EXPLAIN_INITIAL,DBUG_SET,DBUG_SET_INITIAL
DBUG_EVALUATE,DBUG_EVALUATE_IF
libmysql/libmysql.c:
remove _db_on_ and DEBUGGER_ON/OFF
mysys/my_init.c:
missed DBUG_RETURN
mysys/my_thr_init.c:
bugfix - transaction id's are unsigned
mysys/testhash.c:
remove _db_on_ and DEBUGGER_ON/OFF
sql/ha_myisammrg.cc:
missed ;
sql/ha_ndbcluster.cc:
remove _db_on_ and DEBUGGER_ON/OFF
missed ;
sql/ha_ndbcluster_binlog.cc:
remove _db_on_ and DEBUGGER_ON/OFF
missed ;
sql/item_cmpfunc.cc:
missed ;
sql/lock.cc:
missed DBUG_RETURN
sql/log_event.cc:
missed ;
sql/mysqld.cc:
remove _db_on_ and DEBUGGER_ON/OFF
missed ;
DBUG_SET_INITIAL
sql/opt_range.cc:
remove _db_on_ and DEBUGGER_ON/OFF
sql/set_var.cc:
class sys_var_thd_dbug and "debug" server variable
sql/set_var.h:
class sys_var_thd_dbug and "debug" server variable
sql/slave.cc:
missed ;
sql/sql_cache.cc:
missed ;
sql/sql_plugin.cc:
missed ;
sql/sql_select.cc:
remove _db_on_ and DEBUGGER_ON/OFF
storage/heap/hp_test2.c:
remove _db_on_ and DEBUGGER_ON/OFF
storage/myisam/ft_eval.c:
remove _db_on_ and DEBUGGER_ON/OFF
storage/myisam/ft_test1.c:
remove _db_on_ and DEBUGGER_ON/OFF
storage/myisam/mi_open.c:
remove _db_on_ and DEBUGGER_ON/OFF
missed ;
storage/myisam/mi_test1.c:
remove _db_on_ and DEBUGGER_ON/OFF
storage/myisam/mi_test2.c:
remove _db_on_ and DEBUGGER_ON/OFF
storage/myisam/mi_test3.c:
remove _db_on_ and DEBUGGER_ON/OFF
storage/ndb/src/ndbapi/DictCache.cpp:
missed ;
storage/ndb/src/ndbapi/NdbTransaction.cpp:
missed ;
tests/mysql_client_test.c:
remove _db_on_ and DEBUGGER_ON/OFF
2006-02-14 22:36:11 +01:00
|
|
|
static int
|
2005-11-30 01:02:21 +01:00
|
|
|
get_options(int *argc,char ***argv)
|
|
|
|
{
|
|
|
|
int ho_error;
|
2006-01-02 01:40:02 +01:00
|
|
|
char *tmp_string;
|
2005-11-30 01:02:21 +01:00
|
|
|
MY_STAT sbuf; /* Stat information for the data file */
|
|
|
|
|
|
|
|
DBUG_ENTER("get_options");
|
|
|
|
if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
|
|
|
|
exit(ho_error);
|
|
|
|
|
|
|
|
if (!user)
|
|
|
|
user= (char *)"root";
|
|
|
|
|
2006-04-11 22:04:08 +02:00
|
|
|
if (create_string || auto_generate_sql)
|
|
|
|
{
|
|
|
|
if (verbose >= 1)
|
2006-04-11 22:10:11 +02:00
|
|
|
fprintf(stderr, "Turning off preserve-schema!\n");
|
2006-03-29 03:59:11 +02:00
|
|
|
opt_preserve= FALSE;
|
2006-04-11 22:04:08 +02:00
|
|
|
}
|
2006-03-29 03:59:11 +02:00
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
if (auto_generate_sql && (create_string || user_supplied_query))
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
|
|
|
fprintf(stderr,
|
2006-01-02 01:40:02 +01:00
|
|
|
"%s: Can't use --auto-generate-sql when create and query strings are specified!\n",
|
2005-11-30 01:02:21 +01:00
|
|
|
my_progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2006-01-02 05:08:45 +01:00
|
|
|
parse_comma(concurrency_str ? concurrency_str : "1", &concurrency);
|
2005-12-25 11:03:53 +01:00
|
|
|
|
2005-12-29 03:41:06 +01:00
|
|
|
if (lock_directory)
|
|
|
|
snprintf(lock_file_str, FN_REFLEN, "%s/%s", lock_directory, MYSLAPLOCK);
|
|
|
|
else
|
|
|
|
snprintf(lock_file_str, FN_REFLEN, "%s/%s", MYSLAPLOCK_DIR, MYSLAPLOCK);
|
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
if (opt_csv_str)
|
2005-12-25 11:03:53 +01:00
|
|
|
{
|
2005-12-25 00:41:40 +01:00
|
|
|
opt_silent= TRUE;
|
2006-01-02 01:40:02 +01:00
|
|
|
|
|
|
|
if (opt_csv_str[0] == '-')
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-02 01:40:02 +01:00
|
|
|
csv_file= fileno(stdout);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
2006-01-02 01:40:02 +01:00
|
|
|
else
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-02 01:40:02 +01:00
|
|
|
if ((csv_file= my_open(opt_csv_str, O_CREAT|O_WRONLY|O_APPEND, MYF(0)))
|
|
|
|
== -1)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"%s: Could not open csv file: %sn\n",
|
|
|
|
my_progname, opt_csv_str);
|
|
|
|
exit(1);
|
|
|
|
}
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
if (opt_only_print)
|
|
|
|
opt_silent= TRUE;
|
2005-12-25 00:41:40 +01:00
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
if (auto_generate_sql)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2007-01-29 22:17:30 +01:00
|
|
|
unsigned long long x= 0;
|
|
|
|
statement *ptr_statement;
|
|
|
|
|
|
|
|
create_statements= build_table_string();
|
|
|
|
|
|
|
|
if (auto_generate_sql_type[0] == 'r')
|
|
|
|
{
|
|
|
|
for (ptr_statement= create_statements, x= 0;
|
|
|
|
x < auto_generate_sql_number;
|
|
|
|
x++, ptr_statement= ptr_statement->next)
|
|
|
|
{
|
|
|
|
ptr_statement->next= build_insert_string();
|
|
|
|
}
|
|
|
|
|
|
|
|
query_statements= build_query_string();
|
|
|
|
}
|
|
|
|
else if (auto_generate_sql_type[0] == 'w')
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
We generate a number of strings in case the engine is
|
|
|
|
Archive (since strings which were identical one after another
|
|
|
|
would be too easily optimized).
|
|
|
|
*/
|
2006-01-02 01:40:02 +01:00
|
|
|
query_statements= build_insert_string();
|
2007-01-29 22:17:30 +01:00
|
|
|
for (ptr_statement= query_statements, x= 0;
|
|
|
|
x < auto_generate_sql_number;
|
|
|
|
x++, ptr_statement= ptr_statement->next)
|
2006-04-11 22:04:08 +02:00
|
|
|
{
|
2007-01-29 22:17:30 +01:00
|
|
|
ptr_statement->next= build_insert_string();
|
2006-04-11 22:04:08 +02:00
|
|
|
}
|
2007-01-29 22:17:30 +01:00
|
|
|
}
|
|
|
|
else /* Mixed mode is default */
|
|
|
|
{
|
|
|
|
int coin= 0;
|
2006-04-11 22:04:08 +02:00
|
|
|
|
2007-01-29 22:17:30 +01:00
|
|
|
query_statements= build_insert_string();
|
|
|
|
/*
|
|
|
|
This logic should be extended to do a more mixed load,
|
|
|
|
at the moment it results in "every other".
|
|
|
|
*/
|
|
|
|
for (ptr_statement= query_statements, x= 0;
|
|
|
|
x < 4;
|
|
|
|
x++, ptr_statement= ptr_statement->next)
|
|
|
|
{
|
|
|
|
if (coin)
|
|
|
|
{
|
|
|
|
ptr_statement->next= build_insert_string();
|
|
|
|
coin= 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ptr_statement->next= build_query_string();
|
|
|
|
coin= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
2006-01-02 01:40:02 +01:00
|
|
|
else
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-02 01:40:02 +01:00
|
|
|
if (create_string && my_stat(create_string, &sbuf, MYF(0)))
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-02 01:40:02 +01:00
|
|
|
File data_file;
|
|
|
|
if (!MY_S_ISREG(sbuf.st_mode))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"%s: Create file was not a regular file\n",
|
|
|
|
my_progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if ((data_file= my_open(create_string, O_RDWR, MYF(0))) == -1)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"%s: Could not open create file\n", my_progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
tmp_string= (char *)my_malloc(sbuf.st_size+1, MYF(MY_WME));
|
|
|
|
my_read(data_file, tmp_string, sbuf.st_size, MYF(0));
|
|
|
|
tmp_string[sbuf.st_size]= '\0';
|
|
|
|
my_close(data_file,MYF(0));
|
|
|
|
parse_delimiter(tmp_string, &create_statements, delimiter[0]);
|
|
|
|
my_free(tmp_string, MYF(0));
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
2006-01-02 01:40:02 +01:00
|
|
|
else if (create_string)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-02 01:40:02 +01:00
|
|
|
parse_delimiter(create_string, &create_statements, delimiter[0]);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
2005-12-25 00:41:40 +01:00
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
if (user_supplied_query && my_stat(user_supplied_query, &sbuf, MYF(0)))
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-02 01:40:02 +01:00
|
|
|
File data_file;
|
|
|
|
if (!MY_S_ISREG(sbuf.st_mode))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"%s: User query supplied file was not a regular file\n",
|
|
|
|
my_progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if ((data_file= my_open(user_supplied_query, O_RDWR, MYF(0))) == -1)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
tmp_string= (char *)my_malloc(sbuf.st_size+1, MYF(MY_WME));
|
|
|
|
my_read(data_file, tmp_string, sbuf.st_size, MYF(0));
|
|
|
|
tmp_string[sbuf.st_size]= '\0';
|
|
|
|
my_close(data_file,MYF(0));
|
|
|
|
if (user_supplied_query)
|
|
|
|
actual_queries= parse_delimiter(tmp_string, &query_statements,
|
|
|
|
delimiter[0]);
|
|
|
|
my_free(tmp_string, MYF(0));
|
|
|
|
}
|
|
|
|
else if (user_supplied_query)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-02 01:40:02 +01:00
|
|
|
actual_queries= parse_delimiter(user_supplied_query, &query_statements,
|
|
|
|
delimiter[0]);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
if (default_engine)
|
|
|
|
parse_delimiter(default_engine, &engine_statements, ',');
|
2005-12-25 00:41:40 +01:00
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
if (tty_password)
|
|
|
|
opt_password= get_tty_password(NullS);
|
2005-12-03 07:07:11 +01:00
|
|
|
DBUG_RETURN(0);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-04-11 22:04:08 +02:00
|
|
|
static int run_query(MYSQL *mysql, const char *query, int len)
|
|
|
|
{
|
|
|
|
if (opt_only_print)
|
|
|
|
{
|
|
|
|
printf("%.*s;\n", len, query);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verbose >= 2)
|
|
|
|
printf("%.*s;\n", len, query);
|
|
|
|
return mysql_real_query(mysql, query, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
static int
|
2005-12-25 11:03:53 +01:00
|
|
|
create_schema(MYSQL *mysql, const char *db, statement *stmt,
|
|
|
|
statement *engine_stmt)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2005-12-25 00:41:40 +01:00
|
|
|
char query[HUGE_STRING_LENGTH];
|
|
|
|
statement *ptr;
|
2006-04-11 22:04:08 +02:00
|
|
|
int len;
|
2005-11-30 01:02:21 +01:00
|
|
|
DBUG_ENTER("create_schema");
|
|
|
|
|
2006-04-11 22:04:08 +02:00
|
|
|
len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db);
|
|
|
|
|
|
|
|
if (run_query(mysql, query, len))
|
2005-12-25 00:41:40 +01:00
|
|
|
{
|
2006-04-11 22:04:08 +02:00
|
|
|
fprintf(stderr,"%s: Cannot create schema %s : %s\n", my_progname, db,
|
|
|
|
mysql_error(mysql));
|
|
|
|
exit(1);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
2006-04-11 22:04:08 +02:00
|
|
|
if (opt_only_print)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2005-12-25 00:41:40 +01:00
|
|
|
printf("use %s;\n", db);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-04-11 22:04:08 +02:00
|
|
|
if (verbose >= 2)
|
|
|
|
printf("%s;\n", query);
|
2005-12-25 00:41:40 +01:00
|
|
|
if (mysql_select_db(mysql, db))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"%s: Cannot select schema '%s': %s\n",my_progname, db,
|
|
|
|
mysql_error(mysql));
|
|
|
|
exit(1);
|
|
|
|
}
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
if (engine_stmt)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-04-11 22:04:08 +02:00
|
|
|
len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`",
|
|
|
|
engine_stmt->string);
|
|
|
|
if (run_query(mysql, query, len))
|
2005-12-25 00:41:40 +01:00
|
|
|
{
|
2006-04-11 22:04:08 +02:00
|
|
|
fprintf(stderr,"%s: Cannot set default engine: %s\n", my_progname,
|
|
|
|
mysql_error(mysql));
|
|
|
|
exit(1);
|
2005-12-25 00:41:40 +01:00
|
|
|
}
|
|
|
|
}
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2005-12-25 11:03:53 +01:00
|
|
|
for (ptr= stmt; ptr && ptr->length; ptr= ptr->next)
|
2005-12-25 00:41:40 +01:00
|
|
|
{
|
2006-04-11 22:04:08 +02:00
|
|
|
if (run_query(mysql, ptr->string, ptr->length))
|
2005-12-25 00:41:40 +01:00
|
|
|
{
|
2006-04-11 22:04:08 +02:00
|
|
|
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
|
|
|
|
my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
|
|
|
|
exit(1);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2005-12-25 11:03:53 +01:00
|
|
|
drop_schema(MYSQL *mysql, const char *db)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
|
|
|
char query[HUGE_STRING_LENGTH];
|
2006-04-11 22:04:08 +02:00
|
|
|
int len;
|
2005-11-30 01:02:21 +01:00
|
|
|
DBUG_ENTER("drop_schema");
|
2006-04-11 22:04:08 +02:00
|
|
|
len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
|
|
|
|
|
|
|
|
if (run_query(mysql, query, len))
|
2005-12-25 00:41:40 +01:00
|
|
|
{
|
2006-04-11 22:04:08 +02:00
|
|
|
fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
|
|
|
|
my_progname, db, mysql_error(mysql));
|
|
|
|
exit(1);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
2006-04-11 22:04:08 +02:00
|
|
|
|
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
static int
|
|
|
|
run_scheduler(stats *sptr, statement *stmts, uint concur, ulonglong limit)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-11-30 02:40:42 +01:00
|
|
|
#ifndef __WIN__
|
2005-11-30 01:02:21 +01:00
|
|
|
uint x;
|
2006-11-30 02:40:42 +01:00
|
|
|
#endif
|
2005-12-29 03:41:06 +01:00
|
|
|
File lock_file;
|
|
|
|
struct timeval start_time, end_time;
|
2006-01-12 06:30:52 +01:00
|
|
|
thread_context con;
|
2005-12-29 21:29:02 +01:00
|
|
|
DBUG_ENTER("run_scheduler");
|
2005-12-29 03:41:06 +01:00
|
|
|
|
2006-01-12 06:30:52 +01:00
|
|
|
con.stmt= stmts;
|
|
|
|
con.limit= limit;
|
2006-02-19 18:41:59 +01:00
|
|
|
con.thread= opt_use_threads ? 1 :0;
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2005-12-29 03:41:06 +01:00
|
|
|
lock_file= my_open(lock_file_str, O_CREAT|O_WRONLY|O_TRUNC, MYF(0));
|
|
|
|
|
|
|
|
if (!opt_slave)
|
|
|
|
if (my_lock(lock_file, F_WRLCK, 0, F_TO_EOF, MYF(0)))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"%s: Could not get lockfile\n",
|
|
|
|
my_progname);
|
|
|
|
exit(0);
|
|
|
|
}
|
2006-01-02 01:40:02 +01:00
|
|
|
|
2006-02-26 03:03:11 +01:00
|
|
|
#ifdef HAVE_LIBPTHREAD
|
2006-01-12 06:30:52 +01:00
|
|
|
if (opt_use_threads)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-12 06:30:52 +01:00
|
|
|
pthread_t mainthread; /* Thread descriptor */
|
|
|
|
pthread_attr_t attr; /* Thread attributes */
|
|
|
|
|
|
|
|
for (x= 0; x < concur; x++)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-12 06:30:52 +01:00
|
|
|
pthread_attr_init(&attr);
|
|
|
|
pthread_attr_setdetachstate(&attr,
|
|
|
|
PTHREAD_CREATE_DETACHED);
|
|
|
|
|
|
|
|
/* now create the thread */
|
|
|
|
if (pthread_create(&mainthread, &attr, (void *)run_task,
|
|
|
|
(void *)&con) != 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"%s: Could not create thread\n",
|
|
|
|
my_progname);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-02-26 03:03:11 +01:00
|
|
|
#endif
|
2006-03-27 19:25:01 +02:00
|
|
|
#if !(defined(__WIN__) || defined(__NETWARE__))
|
2006-02-26 03:03:11 +01:00
|
|
|
#ifdef HAVE_LIBPTHREAD
|
2006-01-12 06:30:52 +01:00
|
|
|
else
|
2006-02-26 03:03:11 +01:00
|
|
|
#endif
|
2006-01-12 06:30:52 +01:00
|
|
|
{
|
2006-01-12 21:27:25 +01:00
|
|
|
fflush(NULL);
|
2006-01-12 06:30:52 +01:00
|
|
|
for (x= 0; x < concur; x++)
|
|
|
|
{
|
|
|
|
int pid;
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_PRINT("info", ("x: %d concurrency: %u", x, *concurrency));
|
2006-01-12 06:30:52 +01:00
|
|
|
pid= fork();
|
|
|
|
switch(pid)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
/* child */
|
|
|
|
DBUG_PRINT("info", ("fork returned 0, calling task(\"%s\"), pid %d gid %d",
|
2006-04-11 23:24:06 +02:00
|
|
|
stmts ? stmts->string : "", pid, getgid()));
|
2006-01-12 06:30:52 +01:00
|
|
|
if (verbose >= 2)
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: fork returned 0, calling task pid %d gid %d\n",
|
|
|
|
my_progname, pid, getgid());
|
|
|
|
run_task(&con);
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case -1:
|
|
|
|
/* error */
|
|
|
|
DBUG_PRINT("info",
|
|
|
|
("fork returned -1, failing pid %d gid %d", pid, getgid()));
|
2005-11-30 01:02:21 +01:00
|
|
|
fprintf(stderr,
|
2006-01-12 06:30:52 +01:00
|
|
|
"%s: Failed on fork: -1, max procs per parent exceeded.\n",
|
|
|
|
my_progname);
|
|
|
|
/*exit(1);*/
|
|
|
|
goto WAIT;
|
|
|
|
default:
|
|
|
|
/* parent, forked */
|
|
|
|
DBUG_PRINT("info", ("default, break: pid %d gid %d", pid, getgid()));
|
|
|
|
if (verbose >= 2)
|
|
|
|
fprintf(stderr,"%s: fork returned %d, gid %d\n",
|
|
|
|
my_progname, pid, getgid());
|
|
|
|
break;
|
|
|
|
}
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
}
|
2006-01-16 17:35:01 +01:00
|
|
|
#endif
|
2006-01-12 06:30:52 +01:00
|
|
|
|
2005-12-29 03:41:06 +01:00
|
|
|
/* Lets release use some clients! */
|
|
|
|
if (!opt_slave)
|
|
|
|
my_lock(lock_file, F_UNLCK, 0, F_TO_EOF, MYF(0));
|
|
|
|
|
|
|
|
gettimeofday(&start_time, NULL);
|
|
|
|
|
2006-01-12 21:27:25 +01:00
|
|
|
/*
|
|
|
|
We look to grab a write lock at this point. Once we get it we know that
|
|
|
|
all clients have completed their work.
|
|
|
|
*/
|
2006-01-12 06:30:52 +01:00
|
|
|
if (opt_use_threads)
|
|
|
|
{
|
2006-01-12 21:27:25 +01:00
|
|
|
if (my_lock(lock_file, F_WRLCK, 0, F_TO_EOF, MYF(0)))
|
|
|
|
{
|
|
|
|
fprintf(stderr,"%s: Could not get lockfile\n",
|
|
|
|
my_progname);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
my_lock(lock_file, F_UNLCK, 0, F_TO_EOF, MYF(0));
|
2006-01-12 06:30:52 +01:00
|
|
|
}
|
2006-01-16 17:35:01 +01:00
|
|
|
#ifndef __WIN__
|
2006-01-12 06:30:52 +01:00
|
|
|
else
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-12 06:30:52 +01:00
|
|
|
WAIT:
|
|
|
|
while (x--)
|
|
|
|
{
|
|
|
|
int status, pid;
|
|
|
|
pid= wait(&status);
|
|
|
|
DBUG_PRINT("info", ("Parent: child %d status %d", pid, status));
|
2006-03-02 10:48:54 +01:00
|
|
|
if (status != 0)
|
|
|
|
printf("%s: Child %d died with the status %d\n",
|
|
|
|
my_progname, pid, status);
|
2006-01-12 06:30:52 +01:00
|
|
|
}
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
2006-01-16 17:35:01 +01:00
|
|
|
#endif
|
2005-12-29 03:41:06 +01:00
|
|
|
gettimeofday(&end_time, NULL);
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2006-01-12 21:27:25 +01:00
|
|
|
my_close(lock_file, MYF(0));
|
|
|
|
|
2006-01-02 01:40:02 +01:00
|
|
|
sptr->timing= timedif(end_time, start_time);
|
|
|
|
sptr->users= concur;
|
|
|
|
sptr->rows= limit;
|
|
|
|
|
|
|
|
DBUG_RETURN(0);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
2006-07-27 10:54:04 +02:00
|
|
|
|
2005-11-30 01:02:21 +01:00
|
|
|
int
|
2006-01-12 06:30:52 +01:00
|
|
|
run_task(thread_context *con)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-01-02 01:40:02 +01:00
|
|
|
ulonglong counter= 0, queries;
|
2006-02-19 18:41:59 +01:00
|
|
|
File lock_file= -1;
|
|
|
|
MYSQL *mysql;
|
2005-11-30 01:02:21 +01:00
|
|
|
MYSQL_RES *result;
|
|
|
|
MYSQL_ROW row;
|
2006-01-02 01:40:02 +01:00
|
|
|
statement *ptr;
|
2005-11-30 01:02:21 +01:00
|
|
|
|
|
|
|
DBUG_ENTER("run_task");
|
2006-04-11 23:24:06 +02:00
|
|
|
DBUG_PRINT("info", ("task script \"%s\"", con->stmt ? con->stmt->string : ""));
|
2005-11-30 01:02:21 +01:00
|
|
|
|
2006-02-19 18:41:59 +01:00
|
|
|
if (!(mysql= mysql_init(NULL)))
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
if (con->thread && mysql_thread_init())
|
|
|
|
goto end;
|
2005-11-30 01:02:21 +01:00
|
|
|
|
|
|
|
DBUG_PRINT("info", ("trying to connect to host %s as user %s", host, user));
|
2005-12-29 03:41:06 +01:00
|
|
|
lock_file= my_open(lock_file_str, O_RDWR, MYF(0));
|
|
|
|
my_lock(lock_file, F_RDLCK, 0, F_TO_EOF, MYF(0));
|
2006-03-02 10:48:54 +01:00
|
|
|
if (!opt_only_print)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-07-27 10:54:04 +02:00
|
|
|
/* Connect to server */
|
|
|
|
static ulong connection_retry_sleep= 100000; /* Microseconds */
|
|
|
|
int i, connect_error= 1;
|
|
|
|
for (i= 0; i < 10; i++)
|
|
|
|
{
|
|
|
|
if (mysql_real_connect(mysql, host, user, opt_password,
|
2006-04-11 20:49:31 +02:00
|
|
|
create_schema_string,
|
|
|
|
opt_mysql_port,
|
|
|
|
opt_mysql_unix_port,
|
2006-07-27 10:54:04 +02:00
|
|
|
connect_flags))
|
|
|
|
{
|
|
|
|
/* Connect suceeded */
|
|
|
|
connect_error= 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
my_sleep(connection_retry_sleep);
|
|
|
|
}
|
|
|
|
if (connect_error)
|
2005-12-25 00:41:40 +01:00
|
|
|
{
|
2006-07-27 10:54:04 +02:00
|
|
|
fprintf(stderr,"%s: Error when connecting to server: %d %s\n",
|
|
|
|
my_progname, mysql_errno(mysql), mysql_error(mysql));
|
2006-02-19 18:41:59 +01:00
|
|
|
goto end;
|
2005-12-25 00:41:40 +01:00
|
|
|
}
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
DBUG_PRINT("info", ("connected."));
|
2006-04-11 22:04:08 +02:00
|
|
|
if (verbose >= 3)
|
|
|
|
fprintf(stderr, "connected!\n");
|
2006-03-02 10:48:54 +01:00
|
|
|
queries= 0;
|
2005-12-29 03:41:06 +01:00
|
|
|
|
|
|
|
limit_not_met:
|
2006-01-12 06:30:52 +01:00
|
|
|
for (ptr= con->stmt; ptr && ptr->length; ptr= ptr->next)
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-04-11 22:04:08 +02:00
|
|
|
if (run_query(mysql, ptr->string, ptr->length))
|
2005-11-30 01:02:21 +01:00
|
|
|
{
|
2006-04-11 22:04:08 +02:00
|
|
|
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
|
|
|
|
my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
|
|
|
|
goto end;
|
2005-12-25 00:41:40 +01:00
|
|
|
}
|
2006-04-11 22:04:08 +02:00
|
|
|
if (mysql_field_count(mysql))
|
2005-12-25 00:41:40 +01:00
|
|
|
{
|
2006-04-11 22:04:08 +02:00
|
|
|
result= mysql_store_result(mysql);
|
|
|
|
while ((row = mysql_fetch_row(result)))
|
|
|
|
counter++;
|
|
|
|
mysql_free_result(result);
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
2005-12-29 03:41:06 +01:00
|
|
|
queries++;
|
|
|
|
|
2006-01-12 06:30:52 +01:00
|
|
|
if (con->limit && queries == con->limit)
|
2006-02-19 18:41:59 +01:00
|
|
|
goto end;
|
2005-11-30 01:02:21 +01:00
|
|
|
}
|
|
|
|
|
2007-01-29 22:17:30 +01:00
|
|
|
if (con->limit && queries < con->limit)
|
2006-04-11 22:23:16 +02:00
|
|
|
goto limit_not_met;
|
2005-12-29 03:41:06 +01:00
|
|
|
|
2006-02-19 18:41:59 +01:00
|
|
|
end:
|
|
|
|
|
|
|
|
if (lock_file != -1)
|
|
|
|
{
|
|
|
|
my_lock(lock_file, F_UNLCK, 0, F_TO_EOF, MYF(0));
|
|
|
|
my_close(lock_file, MYF(0));
|
|
|
|
}
|
2005-12-29 03:41:06 +01:00
|
|
|
|
2005-12-25 00:41:40 +01:00
|
|
|
if (!opt_only_print)
|
2006-02-19 18:41:59 +01:00
|
|
|
mysql_close(mysql);
|
2005-12-29 03:41:06 +01:00
|
|
|
|
2006-02-19 18:41:59 +01:00
|
|
|
if (con->thread)
|
|
|
|
my_thread_end();
|
2005-11-30 01:02:21 +01:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
2005-12-25 00:41:40 +01:00
|
|
|
|
2005-12-25 11:03:53 +01:00
|
|
|
|
|
|
|
uint
|
|
|
|
parse_delimiter(const char *script, statement **stmt, char delm)
|
2005-12-25 00:41:40 +01:00
|
|
|
{
|
|
|
|
char *retstr;
|
|
|
|
char *ptr= (char *)script;
|
|
|
|
statement **sptr= stmt;
|
|
|
|
statement *tmp;
|
|
|
|
uint length= strlen(script);
|
2006-01-02 01:35:30 +01:00
|
|
|
uint count= 0; /* We know that there is always one */
|
2005-12-25 00:41:40 +01:00
|
|
|
|
2005-12-25 11:03:53 +01:00
|
|
|
for (tmp= *sptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL));
|
|
|
|
(retstr= strchr(ptr, delm));
|
2005-12-25 00:41:40 +01:00
|
|
|
tmp->next= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL)),
|
|
|
|
tmp= tmp->next)
|
|
|
|
{
|
2005-12-25 11:03:53 +01:00
|
|
|
count++;
|
2006-01-26 04:54:42 +01:00
|
|
|
tmp->string= my_strndup(ptr, (size_t)(retstr - ptr), MYF(MY_FAE));
|
2005-12-25 11:03:53 +01:00
|
|
|
tmp->length= (size_t)(retstr - ptr);
|
|
|
|
ptr+= retstr - ptr + 1;
|
2005-12-25 00:41:40 +01:00
|
|
|
if (isspace(*ptr))
|
|
|
|
ptr++;
|
2005-12-25 11:03:53 +01:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr != script+length)
|
|
|
|
{
|
2006-01-26 04:54:42 +01:00
|
|
|
tmp->string= my_strndup(ptr, (size_t)((script + length) - ptr),
|
2005-12-25 11:03:53 +01:00
|
|
|
MYF(MY_FAE));
|
|
|
|
tmp->length= (size_t)((script + length) - ptr);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint
|
|
|
|
parse_comma(const char *string, uint **range)
|
|
|
|
{
|
2006-01-02 01:35:30 +01:00
|
|
|
uint count= 1,x; /* We know that there is always one */
|
2005-12-25 11:03:53 +01:00
|
|
|
char *retstr;
|
|
|
|
char *ptr= (char *)string;
|
|
|
|
uint *nptr;
|
|
|
|
|
|
|
|
for (;*ptr; ptr++)
|
|
|
|
if (*ptr == ',') count++;
|
|
|
|
|
2006-01-02 01:35:30 +01:00
|
|
|
/* One extra spot for the NULL */
|
2005-12-25 11:03:53 +01:00
|
|
|
nptr= *range= (uint *)my_malloc(sizeof(uint) * (count + 1), MYF(MY_ZEROFILL));
|
|
|
|
|
|
|
|
ptr= (char *)string;
|
|
|
|
x= 0;
|
|
|
|
while ((retstr= strchr(ptr,',')))
|
|
|
|
{
|
|
|
|
nptr[x++]= atoi(ptr);
|
|
|
|
ptr+= retstr - ptr + 1;
|
2005-12-25 00:41:40 +01:00
|
|
|
}
|
2005-12-25 11:03:53 +01:00
|
|
|
nptr[x++]= atoi(ptr);
|
2005-12-25 00:41:40 +01:00
|
|
|
|
2005-12-25 11:03:53 +01:00
|
|
|
return count;
|
2005-12-25 00:41:40 +01:00
|
|
|
}
|
2006-01-02 01:40:02 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
print_conclusions(conclusions *con)
|
|
|
|
{
|
|
|
|
printf("Benchmark\n");
|
|
|
|
if (con->engine)
|
|
|
|
printf("\tRunning for engine %s\n", con->engine);
|
|
|
|
printf("\tAverage number of seconds to run all queries: %ld.%03ld seconds\n",
|
|
|
|
con->avg_timing / 1000, con->avg_timing % 1000);
|
|
|
|
printf("\tMinimum number of seconds to run all queries: %ld.%03ld seconds\n",
|
|
|
|
con->min_timing / 1000, con->min_timing % 1000);
|
|
|
|
printf("\tMaximum number of seconds to run all queries: %ld.%03ld seconds\n",
|
|
|
|
con->max_timing / 1000, con->max_timing % 1000);
|
|
|
|
printf("\tNumber of clients running queries: %d\n", con->users);
|
|
|
|
printf("\tAverage number of queries per client: %llu\n", con->avg_rows);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
print_conclusions_csv(conclusions *con)
|
|
|
|
{
|
|
|
|
char buffer[HUGE_STRING_LENGTH];
|
|
|
|
snprintf(buffer, HUGE_STRING_LENGTH,
|
|
|
|
"%s,query,%ld.%03ld,%ld.%03ld,%ld.%03ld,%d,%llu\n",
|
2006-01-02 05:27:24 +01:00
|
|
|
con->engine ? con->engine : "", /* Storage engine we ran against */
|
|
|
|
con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */
|
|
|
|
con->min_timing / 1000, con->min_timing % 1000, /* Min time */
|
|
|
|
con->max_timing / 1000, con->max_timing % 1000, /* Max time */
|
|
|
|
con->users, /* Children used */
|
|
|
|
con->avg_rows /* Queries run */
|
2006-01-02 01:40:02 +01:00
|
|
|
);
|
|
|
|
my_write(csv_file, buffer, strlen(buffer), MYF(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
generate_stats(conclusions *con, statement *eng, stats *sptr)
|
|
|
|
{
|
|
|
|
stats *ptr;
|
|
|
|
int x;
|
|
|
|
|
|
|
|
con->min_timing= sptr->timing;
|
|
|
|
con->max_timing= sptr->timing;
|
|
|
|
con->min_rows= sptr->rows;
|
|
|
|
con->max_rows= sptr->rows;
|
|
|
|
|
2006-01-02 05:27:24 +01:00
|
|
|
/* At the moment we assume uniform */
|
2006-01-02 01:40:02 +01:00
|
|
|
con->users= sptr->users;
|
|
|
|
con->avg_rows= sptr->rows;
|
|
|
|
|
2006-01-02 05:27:24 +01:00
|
|
|
/* With no next, we know it is the last element that was malloced */
|
2006-01-03 11:09:18 +01:00
|
|
|
for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
|
2006-01-02 01:40:02 +01:00
|
|
|
{
|
|
|
|
con->avg_timing+= ptr->timing;
|
|
|
|
|
|
|
|
if (ptr->timing > con->max_timing)
|
|
|
|
con->max_timing= ptr->timing;
|
|
|
|
if (ptr->timing < con->min_timing)
|
|
|
|
con->min_timing= ptr->timing;
|
|
|
|
}
|
|
|
|
con->avg_timing= con->avg_timing/iterations;
|
|
|
|
|
|
|
|
if (eng && eng->string)
|
|
|
|
con->engine= eng->string;
|
|
|
|
else
|
|
|
|
con->engine= NULL;
|
|
|
|
}
|
2006-01-02 05:08:45 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
statement_cleanup(statement *stmt)
|
|
|
|
{
|
|
|
|
statement *ptr, *nptr;
|
|
|
|
if (!stmt)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (ptr= stmt; ptr; ptr= nptr)
|
|
|
|
{
|
|
|
|
nptr= ptr->next;
|
|
|
|
if (ptr->string)
|
|
|
|
my_free(ptr->string, MYF(0));
|
|
|
|
my_free((byte *)ptr, MYF(0));
|
|
|
|
}
|
|
|
|
}
|