#! /usr/bin/env perl

# Copyright (C) 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA

use lib 'lib';
use lib "$ENV{RQG_HOME}/lib";
use lib 'randgen/lib';

use strict;
use Carp;
use Cwd;
use DBI;
use File::Find;
use Getopt::Long;
use POSIX;
use Sys::Hostname;

use GenTest;
use GenTest::Properties;
use GenTest::Constants;

# TODO:
#  - clean up imports (use) not used.
#  - fix description after adjusting calling scripts (PB2)
#  - handle env vars RQG_HOME / RQG_CONF?
#  - add support for skipping tests and printing message (e.g.: If plugin not found)
#  - make basedir option a hash, skip basedirForRelease option?
#  - Reporting: Check and fix? More flexibility needed?
#  - propagate MTR_BUILD_THREAD / MTR_PORT_BASE, if needed?
#  - make vardir optional (mandatory vardir conflicts with --mem / MTR_MEM=1)
#  - add to help text (see sub help())
#  - add logic for process cleanup (left-over mysqlds), at least if Pushbuild
#  - more defaults?
#  - exit safely
#  - See also other TODO comments below.

################################################################################
#
# DRAFT - INCOMPLETE - DRAFT - INCOMPLETE - DRAFT
#
# This script is a wrapper around certain RQG functionality, primarily running
# well-defined RQG tests in a convenient way.
#
# The script accepts arguments which uniquely identify the test case to be run.
# From this identifier the script grabs information from a separate file which
# defines the test case, including various options to the RQG and MySQL.
# Then, the RQG's runall.pl script is executed with the options gathered from
# the test definition. Options may be overridden on the command line.
# The runall.pl script takes care of starting the database server as well as
# executing the test itself.
#
# MySQL/Sun/Oracle notes:
#
# This script implements the interface between Pushbuild (automated testing
# infrastructure) and the Random Query Generator.
# The script is invoked by Pushbuild (PB2) slave instances when they have a job
# matching certain conditions.
# See tests_systemqa.py in pb2-trd-config repository for details.
#
# Pushbuild always provides the following arguments/oiptions to this script:
#   --basedir : Location of binaries to be tested
#   --vardir  : Location of temporary test files (logs, database, etc.)
#   --branch  : MySQL bazaar source code branch nick or other identifier
#               corresponding to the given binaries.
#   --config  : File specifying which test specification to use.
#               The test specification contains test name, options, etc.
#
# We hope to merge/integrate this with what is currently runall.pl and the
# new modules for server start that is being developed, eventually.
################################################################################

#
# See bottom of file for subroutines.
#

# Autoflush output buffers (needed when using POSIX::_exit())
$| = 1;

# Show in output when this script starts for ease of debugging when wrapped
# inside other scripts.
say("==================== Starting $0 ====================\n");

# Find out if this is Pushbuild (MySQL's automatic test system).
# We assume this is Pushbuild if environment variable PB2WORKDIR is set.
my $pushbuild = 1 if defined $ENV{'PB2WORKDIR'};

################################################################################
# Option handling
################################################################################

# We require --config to specify a test definition file.
# Properties.pm treats this option in a special way: As a file containing other
# options.
#
# Options set in this config file may be overridden on the command line.
# The resulting (merged) set of options is then passed to the RQG itself.
# Note: When given on command line, mysqld options should not include 'inner'
#       "--" prefix, e.g. "--mysqld=--lock-wait-timeout=2". Because prefixes
#       will be added automatically, specify "--mysqld=lock-wait-timeout=2"
#       or "--mysqld lock-wait-timeout=2" instead
#       (TODO: Add logic to handle inner -- on command line?).
#
# TODO: Have runall.pl use GenTest::Properties as well.
#
# Consider: Accept --test on command line and find test definition file based
#           on this (see parsing of such a file in lib/GenTest/App/Gendata.pm),
#           instead of having config as a special value, with path and all.

# Read options.
# old: my ($basedir, $vardir, $tree, $test) = @ARGV;
# new: We use GenTest::Properties mechanisms

my @ARGV_saved = @ARGV;

# Print full command line used for calling this script, so that it will appear
# in logs and can be repeated relatively easily.
# Avoiding say()'s prefixing to make it easy to copy & paste.
say("\nInbound command line was: ");
print("$0 \\ \n ".join(" \\ \n ", @ARGV_saved)."\n");

my $options = {};
my $opt_result = GetOptions($options,
    'basedir=s',
    'category=s',
    'config=s',     # The actual test definition, containing options.
    'grammar=s',
    'name=s',
    'vardir=s',     # TODO: Make optional?
    'basedirForRelease:s%',  # hash of paths to basedir for releases to test/compare
    'branch:s',     # TODO: Remove, get from ENV{BRANCH_NAME} instead if needed?
    'candidate:s',
    'dry_run',
    'duration:s',
    'help',
    'mysqld:s%',
    'threads:s',
    'verbose!'
    );
my $config = GenTest::Properties->new(
    options => $options,
    legal => [
        # Adds to the union of $options, $required and $defaults. Include here
        # options that may be specified in separate files, otherwise they
        # will be refused ($options only includes options actually given on
        # the command line).
        'basedir',
        'basedirForRelease',
        'candidate',
        'category',
        'description',
        'dry_run',
        'grammar',
        'help',
        'mysqld',
        'name',
        'threads',
        'vardir',
    ],
    required => [
        'basedir',          # Need to know what to test (binaries)
        'category',         # A test with unknown category is not well-defined.
        'config',           # File specifying a test. Used for forcing a well-defined approach.
        'grammar',          # No random queries without a grammar...
        'name'              # So that we can refer to it later and report results.
        ],
    defaults => {
        threads     => 1,       # Keep it simple by default.
        duration    => 300,     # Suitable for regular automated 'regression testing'
        candidate   => '',
        verbose     => '',
        basedirForRelease => {  # Locations of binaries for various releases
            '5.0' => osWindows() ?
                        'G:\mysql-releases\mysql-5.0.87-win32' :
                        '/export/home/mysql-releases/mysql-5.0'
        }
    },
    help => \&help
);

# Print help text if --help or no options were specified
$config->printHelp if not $opt_result or $config->help;

# List of options that are to be sent to the RQG runner script if defined.
my @randgen_opts_noprefix = (
    'basedir',
    'vardir',
    'grammar',
    'threads',
    'duration'
);

### Process options...

# Get list of options as string with appropriate prefixes.
my $mysqld_options = $config->genOpt('--mysqld=--', 'mysqld');
my $randgen_opts = $config->collectOpt('--', @randgen_opts_noprefix);
#say(my $all_non_complex_opts = $config->collectOpt('--'));

### Set helper variables
# candidate: Match only exact string 'true' (case insensitive)
# Candidate tests may be treated differently e.g. wrt. reporting.
my $candidate = 1 if $config->candidate =~ m{^true$}io;
my $spec_file = $config->config;      # file with test definition

################################################################################
# Prepare test, display info.
################################################################################

say("Loaded test definition from file " . $spec_file) if $spec_file;

#
# Prepare ENV variables and other settings.
#
setupPushbuildEnv() if ($pushbuild);

#
# Print easy-to-read info about the environment (useful for debugging etc.)
#
say("\n======== Information on the host system: ========");
say(" - Local time  : ".localtime());
say(" - Hostname    : ".hostname());
say(" - PID         : $$");
say(" - Working dir : ".cwd());
say(" - PATH        : ".$ENV{'PATH'});

say("\n======== Configuration: ========");
$config->printProps();  # TODO or not TODO? Useful or cluttering? Repeated in gentest?

# TODO: Only if this is a bzr branch and bzr is available...
#say("===== Information on Random Query Generator version (bzr): =====\n");
#system("bzr info");
#system("bzr version-info");
#say("\n");

# Print MTR-style output saying which test suite/mode this is.
# Needed for Pushbuild reporting. The Pushbuild parser requires a certain format
# of the output.
# NOTE: So far we only support running one test at a time, so we only do this
#       here.
print("\n");
print("#" x 78 . "\n");
print("# " . $config->name . "\n");
print("#" x 78 . "\n");
print("\n");

## Debug/development output, temporary only?:
#say("Test description:");
#print("\n--------------------\n".$config->description . "\n---------------------\n\n");

say("This is a CANDIDATE TEST.") if $candidate;

# TODO: Remove? Require path to test file instead? (e.g. conf/runtime/rqg_info_schema.test)
# If not absolute path, it is relative to cwd at run time.
my $conf = $ENV{RQG_CONF};      # currently not used
$conf = 'conf' if not defined $conf;

################################################################################
# Run the test
################################################################################

# Generate command-line
# TODO: Call/run runall or server+gentest using object/module calls instead.
my $cmd = 'perl runall.pl ' . $randgen_opts . ' ' . $mysqld_options;
$cmd =~ s{[\r\n\t]}{ }sgio;     # remove line breaks and tabs form command

if($config->dry_run) {
    # Display outbound command-line and exit
    $spec_file ? say("Dry run, pretending to run test defined by ".$spec_file."...")
               : say("Dry run, pretending to run test defined on command-line...");
    say($cmd);
    say("\n$0 Done.");
    safe_exit();
}

# run for real, process results, report, etc.
say("Command line:");
say($cmd);
say("");

my $command_result = system($cmd);
# shift result code to the right to obtain the code returned from the called script
my $command_result_shifted = ($command_result >> 8);

################################################################################
# Process results and report.
################################################################################

# TODO

### Report test result in an MTR fashion.
### This is done so that Pushbuild will see it, parse it and add to xref database
### etc.
### Format: TESTSUITE.TESTCASE 'TESTMODE' [ RESULT ]
### Example: ndb.ndb_dd_alter 'InnoDB plugin'     [ fail ]
### Not using TESTMODE for now.

my $full_test_name = $config->category.'.'.$config->name;
# keep test statuses more or less vertically aligned
while (length $full_test_name < 40)
{
	$full_test_name = $full_test_name.' ';
}

if ($command_result_shifted > 0) {
	# test failed
	# Marking candidate test as "experimental" by reporting exp-fail status,
    # as used by Pushbuild. TODO: Support other variations if needed.
	if ($candidate) {
		print($full_test_name." [ exp-fail ]\n");
	} else {
		print($full_test_name." [ fail ]\n");
	}
	say('Command failed with exit code '.$command_result_shifted);
	say('Look above this message in the test log for failure details.');
} else {
	print($full_test_name." [ pass ]\n");
}

################################################################################
# Clean up
################################################################################

say("\n$0 Done\n");

################################################################################
# Subroutines
################################################################################

###
### Displays help text. TODO: List more / all options?
###
sub help {

    print <<EOF

###### Help for $0 - Testing via random query generation ######

 Options:

    --basedir   : Top-level directory (basedir) of the database installation to be tested.
    --config    : Path to configuration file specifying a set of options, e.g. a test definition (.test).
                  Options specified in the config file can be overridden on the command-line.
    --dry_run   : Do not actually run the test, but process options and show resulting commands.
    --help      : Display this help message.

    Example command-line:
        $0 --config=conf/examples/example.test --basedir=/home/user/mysql-trunk --duration=60

        This says "Run the test example.test found here... and set duration to 60 seconds".
        Other required options are set in the example.test file.

    Example .test file (for --config option):

        {
            name        => 'rqg_example',
            category    => 'example',
            description => 'Example test showing how to use the RQG',
            grammar     => 'conf/examples/example.yy',
            threads     => 5,
            mysqld      => {
                'log-output' => 'file'
            }
        }

    Command line options override options in --config file.

EOF
	;
	safe_exit(1);
}

###
### Sets up environment variables and other stuff required when running in
### MySQL's Pushbuild environment.
###
sub setupPushbuildEnv {
    if (osWindows()) {
        # For tail and for cdb
        # TODO: Remove randgen\bin, not used?
        $ENV{PATH} =
            'G:\pb2\scripts\randgen\bin'.
            ';G:\pb2\scripts\bin;C:\Program Files\Debugging Tools for Windows (x86)'.
            ';'.$ENV{PATH};

        # For cdb (stack traces)
        $ENV{_NT_SYMBOL_PATH} = 'srv*c:\\cdb_symbols*http://msdl.microsoft.com/download/symbols;cache*c:\\cdb_symbols';

        # For vlad (~2008-09)
        #ENV{MYSQL_FULL_MINIDUMP} = 1;

    } elsif (osSolaris()) {
        # For libmysqlclient
        $ENV{LD_LIBRARY_PATH} =
            $ENV{LD_LIBRARY_PATH}.
            ':/export/home/pb2/scripts/lib/';

        # For DBI and DBD::mysql (on hosts with special Perl setup)
        $ENV{PERL5LIB} =
            $ENV{PERL5LIB}.
            ':/export/home/pb2/scripts/DBI-1.607/'.
            ':/export/home/pb2/scripts/DBI-1.607/lib'.
            ':/export/home/pb2/scripts/DBI-1.607/blib/arch/'.
            ':/export/home/pb2/scripts/DBD-mysql-4.008/lib/'.
            ':/export/home/pb2/scripts/DBD-mysql-4.008/blib/arch/';

        # For c++filt
        $ENV{PATH} = $ENV{PATH}.':/opt/studio12/SUNWspro/bin';
    }

    # We currently assume current working dir is a 'scripts' directory
    # containing a copy of the random query generator.
    # Make sure current working dir is the top-level randgen dir.
    # TODO: Check if really needed.
    chdir('randgen');
}


#!/usr/bin/perl

# Copyright (c) 2010,2011 Oracle and/or its affiliates. All rights reserved.
# Use is subject to license terms.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA

#################### FOR THE MOMENT THIS SCRIPT IS FOR TESTING PURPOSES

use lib 'lib';
use lib "$ENV{RQG_HOME}/lib";
use Carp;
use strict;
use GenTest;
use GenTest::BzrInfo;
use GenTest::Constants;
use GenTest::Properties;
use GenTest::App::GenTest;
use DBServer::DBServer;
use DBServer::MySQL::MySQLd;
use DBServer::MySQL::ReplMySQLd;

my $logger;
eval
{
    require Log::Log4perl;
    Log::Log4perl->import();
    $logger = Log::Log4perl->get_logger('randgen.gentest');
};

$| = 1;
if (osWindows()) {
	$SIG{CHLD} = "IGNORE";
}

if (defined $ENV{RQG_HOME}) {
    if (osWindows()) {
        $ENV{RQG_HOME} = $ENV{RQG_HOME}.'\\';
    } else {
        $ENV{RQG_HOME} = $ENV{RQG_HOME}.'/';
    }
}

use Getopt::Long;
use GenTest::Constants;
use DBI;
use Cwd;

my $database = 'test';
my @dsns;

my ($gendata, @basedirs, @mysqld_options, @vardirs, $rpl_mode,
    $engine, $help, $debug, @validators, @reporters, @transformers,
    $grammar_file, $skip_recursive_rules,
    $redefine_file, $seed, $mask, $mask_level, $mem, $rows,
    $varchar_len, $xml_output, $valgrind, @valgrind_options, $views,
    $start_dirty, $filter, $build_thread, $sqltrace, $testname,
    $report_xml_tt, $report_xml_tt_type, $report_xml_tt_dest,
    $notnull, $logfile, $logconf, $report_tt_logdir, $querytimeout, $no_mask,
    $short_column_names, $strict_fields, $freeze_time);

my $gendata=''; ## default simple gendata

my $threads = my $default_threads = 10;
my $queries = my $default_queries = 1000;
my $duration = my $default_duration = 3600;

my @ARGV_saved = @ARGV;

my $opt_result = GetOptions(
	'mysqld=s@' => \$mysqld_options[0],
	'mysqld1=s@' => \$mysqld_options[0],
	'mysqld2=s@' => \$mysqld_options[1],
    'basedir=s' => \$basedirs[0],
    'basedir1=s' => \$basedirs[0],
    'basedir2=s' => \$basedirs[1],
	#'basedir=s@' => \@basedirs,
	'vardir=s' => \$vardirs[0],
	'vardir1=s' => \$vardirs[0],
	'vardir2=s' => \$vardirs[1],
	#'vardir=s@' => \@vardirs,
	'rpl_mode=s' => \$rpl_mode,
	'engine=s' => \$engine,
	'grammar=s' => \$grammar_file,
	'skip-recursive-rules' > \$skip_recursive_rules,
	'redefine=s' => \$redefine_file,
	'threads=i' => \$threads,
	'queries=s' => \$queries,
	'duration=i' => \$duration,
	'help' => \$help,
	'debug' => \$debug,
	'validators=s@' => \@validators,
	'reporters=s@' => \@reporters,
	'transformers=s@' => \@transformers,
	'gendata:s' => \$gendata,
	'notnull' => \$notnull,
	'short_column_names' => \$short_column_names,
    'freeze_time' => \$freeze_time,
	'strict_fields' => \$strict_fields,
	'seed=s' => \$seed,
	'mask=i' => \$mask,
    'mask-level=i' => \$mask_level,
	'mem' => \$mem,
	'rows=i' => \$rows,
	'varchar-length=i' => \$varchar_len,
	'xml-output=s'	=> \$xml_output,
	'report-xml-tt'	=> \$report_xml_tt,
	'report-xml-tt-type=s' => \$report_xml_tt_type,
	'report-xml-tt-dest=s' => \$report_xml_tt_dest,
	'testname=s'		=> \$testname,
	'valgrind!'	=> \$valgrind,
	'valgrind_options=s@'	=> \@valgrind_options,
	'views:s'		=> \$views,
	'start-dirty'	=> \$start_dirty,
	'filter=s'	=> \$filter,
    'mtr-build-thread=i' => \$build_thread,
    'sqltrace:s' => \$sqltrace,
    'logfile=s' => \$logfile,
    'logconf=s' => \$logconf,
    'report-tt-logdir=s' => \$report_tt_logdir,
    'querytimeout=i' => \$querytimeout,
    'no-mask' => \$no_mask
    );

if (defined $logfile && defined $logger) {
    setLoggingToFile($logfile);
} else {
    if (defined $logconf && defined $logger) {
        setLogConf($logconf);
    }
}

if (!$opt_result || $help || $basedirs[0] eq '' || not defined $grammar_file) {
	help();
	exit($help ? 0 : 1);
}

if (defined $sqltrace) {
    # --sqltrace may have a string value (optional).
    # Allowed values for --sqltrace:
    my %sqltrace_legal_values = (
        'MarkErrors'    => 1  # Prefixes invalid SQL statements for easier post-processing
    );

    if (length($sqltrace) > 0) {
        # A value is given, check if it is legal.
        if (not exists $sqltrace_legal_values{$sqltrace}) {
            say("Invalid value for --sqltrace option: '$sqltrace'");
            say("Valid values are: ".join(', ', keys(%sqltrace_legal_values)));
            say("No value means that default/plain sqltrace will be used.");
            exit(STATUS_ENVIRONMENT_FAILURE);
        }
    } else {
        # If no value is given, GetOpt will assign the value '' (empty string).
        # We interpret this as plain tracing (no marking of errors, prefixing etc.).
        # Better to use 1 instead of empty string for comparisons later.
        $sqltrace = 1;
    }
}

say("Copyright (c) 2010,2011 Oracle and/or its affiliates. All rights reserved. Use is subject to license terms.");
say("Please see http://forge.mysql.com/wiki/Category:RandomQueryGenerator for more information on this test framework.");
say("Starting \n# $0 \\ \n# ".join(" \\ \n# ", @ARGV_saved));

#
# Calculate master and slave ports based on MTR_BUILD_THREAD (MTR
# Version 1 behaviour)
#

if (not defined $build_thread) {
    if (defined $ENV{MTR_BUILD_THREAD}) {
        $build_thread = $ENV{MTR_BUILD_THREAD}
    } else {
        $build_thread = DEFAULT_MTR_BUILD_THREAD;
    }
}

if ( $build_thread eq 'auto' ) {
    say ("Please set the environment variable MTR_BUILD_THREAD to a value <> 'auto' (recommended) or unset it (will take the value ".DEFAULT_MTR_BUILD_THREAD.") ");
    exit (STATUS_ENVIRONMENT_FAILURE);
}

my @ports = (10000 + 10 * $build_thread, 10000 + 10 * $build_thread + 2);

say("master_port : $ports[0] slave_port : $ports[1] ports : @ports MTR_BUILD_THREAD : $build_thread ");

#
# If the user has provided two vardirs and one basedir, start second
# server using the same basedir
#

if (
	($vardirs[1] ne '') &&
	($basedirs[1] eq '')
    ) {
	$basedirs[1] = $basedirs[0];
}

foreach my $dir (cwd(), @basedirs) {
# calling bzr usually takes a few seconds...
    if (defined $dir) {
        my $bzrinfo = GenTest::BzrInfo->new(
            dir => $dir
            );
        my $revno = $bzrinfo->bzrRevno();
        my $revid = $bzrinfo->bzrRevisionId();

        if ((defined $revno) && (defined $revid)) {
            say("$dir Revno: $revno");
            say("$dir Revision-Id: $revid");
        } else {
            say($dir.' does not look like a bzr branch, cannot get revision info.');
        }
    }
}

if (
	($mysqld_options[1] ne '') &&
	($basedirs[1] eq '')
    ) {
	$basedirs[1] = $basedirs[0];
}

#
# If the user has provided identical basedirs and vardirs, warn of a
# potential overlap.
#

if (
	($basedirs[0] eq $basedirs[1]) &&
	($vardirs[0] eq $vardirs[1]) &&
	($rpl_mode eq '')
    ) {
	croak("Please specify either different --basedir[12] or different --vardir[12] in order to start two MySQL servers");
}

my $client_basedir;

foreach my $path ("$basedirs[0]/client/RelWithDebInfo", "$basedirs[0]/client/Debug", "$basedirs[0]/client", "$basedirs[0]/bin") {
	if (-e $path) {
		$client_basedir = $path;
		last;
	}
}

#
# Start servers. Use rpl_alter if replication is needed.
#

my @server;
my $rplsrv;

if ($rpl_mode ne '') {
    my @options;
    push @options, lc("--$engine") if defined $engine && lc($engine) ne lc('myisam');

    push @options, "--sql-mode=no_engine_substitution" if join(' ', @ARGV_saved) !~ m{sql-mode}io;

    if (defined $mysqld_options[0]) {
        push @options, @{$mysqld_options[0]};
    }
    $rplsrv = DBServer::MySQL::ReplMySQLd->new(basedir => $basedirs[0],
                                               master_vardir => $vardirs[0],
                                               master_port => $ports[0],
                                               slave_vardir => $vardirs[1],
                                               slave_port => $ports[1],
                                               mode => $rpl_mode,
                                               server_options => \@options,
                                               valgrind => $valgrind,
                                               valgrind_options => \@valgrind_options,
                                               general_log => 1,
                                               start_dirty => $start_dirty);

    my $status = $rplsrv->startServer();

    if ($status > DBSTATUS_OK) {
        stopServers();
        if (osWindows()) {
            say(system("dir ".unix2winPath($rplsrv->master->datadir)));
            say(system("dir ".unix2winPath($rplsrv->slave->datadir)));
        } else {
            say(system("ls -l ".$rplsrv->master->datadir));
            say(system("ls -l ".$rplsrv->slave->datadir));
        }
        croak("Could not start replicating server pair");
    }

    $dsns[0] = $rplsrv->master->dsn($database);
    $dsns[1] = undef; ## passed to gentest. No dsn for slave!
    $server[0] = $rplsrv->master;
    $server[1] = $rplsrv->slave;

} else {
    if ($#basedirs != $#vardirs) {
        croak ("The number of basedirs and vardirs must match $#basedirs != $#vardirs")
    }
    foreach my $server_id (0..1) {
        next if $basedirs[$server_id] eq '';

        my @options;
        push @options, lc("--$engine") if defined $engine && lc($engine) ne lc('myisam');

        push @options, "--sql-mode=no_engine_substitution" if join(' ', @ARGV_saved) !~ m{sql-mode}io;

        if (defined $mysqld_options[$server_id]) {
            push @options, @{$mysqld_options[$server_id]};
        }
        $server[$server_id] = DBServer::MySQL::MySQLd->new(basedir => $basedirs[$server_id],
                                                           vardir => $vardirs[$server_id],
                                                           port => $ports[$server_id],
                                                           start_dirty => $start_dirty,
                                                           valgrind => $valgrind,
                                                           valgrind_options => \@valgrind_options,
                                                           server_options => \@options,
                                                           general_log => 1);

        my $status = $server[$server_id]->startServer;

        if ($status > DBSTATUS_OK) {
            stopServers();
            if (osWindows()) {
                say(system("dir ".unix2winPath($server[$server_id]->datadir)));
            } else {
                say(system("ls -l ".$server[$server_id]->datadir));
            }
            croak("Could not start all servers");
        }

        if (
            ($server_id == 0) ||
            ($rpl_mode eq '')
            ) {
            $dsns[$server_id] = $server[$server_id]->dsn($database);
        }

        if ((defined $dsns[$server_id]) && (defined $engine)) {
            my $dbh = DBI->connect($dsns[$server_id], undef, undef, { RaiseError => 1 } );
            $dbh->do("SET GLOBAL storage_engine = '$engine'");
        }
    }
}

#
# Run actual queries
#

my $gentestProps = GenTest::Properties->new(
    legal => ['grammar',
              'skip-recursive-rules',
              'dsn',
              'engine',
              'gendata',
              'generator',
              'redefine',
              'threads',
              'queries',
              'duration',
              'help',
              'debug',
              'rpl_mode',
              'validators',
              'reporters',
              'reporters',
              'transformers',
              'seed',
              'mask',
              'mask-level',
              'rows',
              'varchar-length',
              'xml-output',
              'views',
              'start-dirty',
              'filter',
              'notnull',
              'short_column_names',
              'strict_fields',
              'freeze_time',
              'valgrind',
              'valgrind-xml',
              'testname',
              'sqltrace',
              'querytimeout',
              'report-xml-tt',
              'report-xml-tt-type',
              'report-xml-tt-dest',
              'logfile',
              'logconf',
              'report-tt-logdir']
    );

my @gentest_options;

## For backward compatability
if ($#validators == 0 and $validators[0] =~ m/,/) {
    @validators = split(/,/,$validators[0]);
}

## For backward compatability
if ($#reporters == 0 and $reporters[0] =~ m/,/) {
    @reporters = split(/,/,$reporters[0]);
}

## For backward compatability
if ($#transformers == 0 and $transformers[0] =~ m/,/) {
    @transformers = split(/,/,$transformers[0]);
}

$gentestProps->property('generator','FromGrammar') if not defined $gentestProps->property('generator');

$gentestProps->property('start-dirty',1) if defined $start_dirty;
$gentestProps->gendata($gendata);
$gentestProps->engine($engine) if defined $engine;
$gentestProps->rpl_mode($rpl_mode) if defined $rpl_mode;
$gentestProps->validators(\@validators) if @validators;
$gentestProps->reporters(\@reporters) if @reporters;
$gentestProps->transformers(\@transformers) if @transformers;
$gentestProps->threads($threads) if defined $threads;
$gentestProps->queries($queries) if defined $queries;
$gentestProps->duration($duration) if defined $duration;
$gentestProps->dsn(\@dsns) if @dsns;
$gentestProps->grammar($grammar_file);
$gentestProps->property('skip-recursive-rules', $skip_recursive_rules);
$gentestProps->redefine($redefine_file) if defined $redefine_file;
$gentestProps->seed($seed) if defined $seed;
$gentestProps->mask($mask) if (defined $mask) && (not defined $no_mask);
$gentestProps->property('mask-level',$mask_level) if defined $mask_level;
$gentestProps->rows($rows) if defined $rows;
if (defined $views) {
	if ($views eq '1') {
		$gentestProps->property('views', 'UNDEFINED');
	} else {
		$gentestProps->property('views', $views);
	}
}
$gentestProps->property('varchar-length',$varchar_len) if defined $varchar_len;
$gentestProps->property('xml-output',$xml_output) if defined $xml_output;
$gentestProps->debug(1) if defined $debug;
$gentestProps->filter($filter) if defined $filter;
$gentestProps->notnull($notnull) if defined $notnull;
$gentestProps->short_coulmn_names($short_column_names) if defined $short_column_names;
$gentestProps->strict_fields($strict_fields) if defined $strict_fields;
$gentestProps->freeze_time($freeze_time) if defined $freeze_time;
$gentestProps->valgrind(1) if $valgrind;
$gentestProps->sqltrace($sqltrace) if $sqltrace;
$gentestProps->querytimeout($querytimeout) if defined $querytimeout;
$gentestProps->testname($testname) if $testname;
$gentestProps->logfile($logfile) if defined $logfile;
$gentestProps->logconf($logconf) if defined $logconf;
$gentestProps->property('report-tt-logdir',$report_tt_logdir) if defined $report_tt_logdir;
$gentestProps->property('report-xml-tt', 1) if defined $report_xml_tt;
$gentestProps->property('report-xml-tt-type', $report_xml_tt_type) if defined $report_xml_tt_type;
$gentestProps->property('report-xml-tt-dest', $report_xml_tt_dest) if defined $report_xml_tt_dest;

# Push the number of "worker" threads into the environment.
# lib/GenTest/Generator/FromGrammar.pm will generate a corresponding grammar element.
$ENV{RQG_THREADS}= $threads;

my $gentest = GenTest::App::GenTest->new(config => $gentestProps);
my $gentest_result = $gentest->run();
say("GenTest exited with exit status ".status2text($gentest_result)." ($gentest_result)");
exit_test($gentest_result) if $gentest_result > 0;

#
# Compare master and slave, or two masters
#

if ($rpl_mode || (defined $basedirs[1])) {
    if ($rpl_mode ne '') {
        $rplsrv->waitForSlaveSync;
    }

    my @dump_files;

	foreach my $i (0..$#server) {
		$dump_files[$i] = tmpdir()."server_".$$."_".$i.".dump";

		my $dump_result = $server[$i]->dumpdb($database,$dump_files[$i]);
		exit_test($dump_result >> 8) if $dump_result > 0;
	}

	say("Comparing SQL dumps...");
	my $diff_result = system("diff -u $dump_files[0] $dump_files[1]");
	$diff_result = $diff_result >> 8;

	if ($diff_result == 0) {
		say("No differences were found between servers.");
	}

	foreach my $dump_file (@dump_files) {
		unlink($dump_file);
	}

	exit_test($diff_result);
}

stopServers();

sub stopServers {
    if ($rpl_mode ne '') {
        $rplsrv->stopServer();
    } else {
        foreach my $srv (@server) {
            if ($srv) {
                $srv->stopServer;
            }
        }
    }
}

sub help {

	print <<EOF
Copyright (c) 2010,2011 Oracle and/or its affiliates. All rights reserved. Use is subject to license terms.

$0 - Run a complete random query generation test, including server start with replication and master/slave verification

    Options related to one standalone MySQL server:

    --basedir   : Specifies the base directory of the stand-alone MySQL installation;
    --mysqld    : Options passed to the MySQL server
    --vardir    : Optional. (default \$basedir/mysql-test/var);

    Options related to two MySQL servers

    --basedir1  : Specifies the base directory of the first MySQL installation;
    --basedir2  : Specifies the base directory of the second MySQL installation;
    --mysqld1   : Options passed to the first MySQL server
    --mysqld2   : Options passed to the second MySQL server
    --vardir1   : Optional. (default \$basedir1/mysql-test/var);
    --vardir2   : Optional. (default \$basedir2/mysql-test/var);

    General options

    --grammar   : Grammar file to use when generating queries (REQUIRED);
    --redefine  : Grammar file to redefine and/or add rules to the given grammar
    --rpl_mode  : Replication type to use (statement|row|mixed) (default: no replication);
    --vardir1   : Optional.
    --vardir2   : Optional.
    --engine    : Table engine to use when creating tables with gendata (default no ENGINE in CREATE TABLE);
    --threads   : Number of threads to spawn (default $default_threads);
    --queries   : Number of queries to execute per thread (default $default_queries);
    --duration  : Duration of the test in seconds (default $default_duration seconds);
    --validator : The validators to use
    --reporter  : The reporters to use
    --transformer: The transformers to use (turns on --validator=transformer). Accepts comma separated list
    --querytimeout: The timeout to use for the QueryTimeout reporter
    --gendata   : Generate data option. Passed to gentest.pl
    --seed      : PRNG seed. Passed to gentest.pl
    --mask      : Grammar mask. Passed to gentest.pl
    --mask-level: Grammar mask level. Passed to gentest.pl
    --notnull   : Generate all fields with NOT NULL
    --rows      : No of rows. Passed to gentest.pl
    --sqltrace  : Print all generated SQL statements.
                  Optional: Specify --sqltrace=MarkErrors to mark invalid statements.
    --varchar-length: length of strings. passed to gentest.pl
    --xml-outputs: Passed to gentest.pl
    --views     : Generate views. Optionally specify view type (algorithm) as option value. Passed to gentest.pl
    --valgrind  : Passed to gentest.pl
    --filter    : Passed to gentest.pl
    --mem       : Passed to mtr
    --mtr-build-thread:  Value used for MTR_BUILD_THREAD when servers are started and accessed
    --debug     : Debug mode
    --short_column_names: use short column names in gendata (c<number>)
    --strict_fields: Disable all AI applied to columns defined in \$fields in the gendata file. Allows for very specific column definitions
    --freeze_time: Freeze time for each query so that CURRENT_TIMESTAMP gives the same result for all transformers/validators
    --help      : This help message

    If you specify --basedir1 and --basedir2 or --vardir1 and --vardir2, two servers will be started and the results from the queries
    will be compared between them.
EOF
	;
	print "$0 arguments were: ".join(' ', @ARGV_saved)."\n";
	exit_test(STATUS_UNKNOWN_ERROR);
}

sub exit_test {
	my $status = shift;
    stopServers();
	say("[$$] $0 will exit with exit status ".status2text($status). " ($status)");
	safe_exit($status);
}


#!/usr/bin/perl

# Copyright (c) 2008, 2011 Oracle and/or its affiliates. All rights reserved.
# Use is subject to license terms.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA

#
# This script executes the following sequence
#
# $ mysql-test-run.pl --start-and-exit with replication
# $ gentest.pl --gendata
# $ diff master slave
#
#

use lib 'lib';
use lib "$ENV{RQG_HOME}/lib";
use strict;
use GenTest;
use Carp;

my $logger;
eval
{
    require Log::Log4perl;
    Log::Log4perl->import();
    $logger = Log::Log4perl->get_logger('randgen.gentest');
};

use GenTest::BzrInfo;

$| = 1;
if (osWindows()) {
	$SIG{CHLD} = "IGNORE";
}

if (defined $ENV{RQG_HOME}) {
        if (osWindows()) {
                $ENV{RQG_HOME} = $ENV{RQG_HOME}.'\\';
        } else {
                $ENV{RQG_HOME} = $ENV{RQG_HOME}.'/';
        }
}

use Getopt::Long;
use GenTest::Constants;
use DBI;
use Cwd;

my $database = 'test';
my @master_dsns;

my ($gendata, $skip_gendata, @basedirs, @mysqld_options, @vardirs, $rpl_mode,
    $engine, $help, $debug, $validators, $reporters, $grammar_file, $skip_recursive_rules,
    $redefine_file, $seed, $mask, $mask_level, $no_mask, $mem, $rows,
    $varchar_len, $xml_output, $valgrind, $valgrind_xml, $views,
    $start_dirty, $filter, $build_thread, $testname, $report_xml_tt,
    $report_xml_tt_type, $report_xml_tt_dest, $notnull, $sqltrace,
    $lcov, $transformers, $logfile, $logconf, $report_tt_logdir,$querytimeout,
    $short_column_names, $strict_fields, $freeze_time);

my $threads = my $default_threads = 10;
my $queries = my $default_queries = 1000;
my $duration = my $default_duration = 3600;

my @ARGV_saved = @ARGV;

my $opt_result = GetOptions(
	'mysqld=s@' => \$mysqld_options[0],
	'mysqld1=s@' => \$mysqld_options[0],
	'mysqld2=s@' => \$mysqld_options[1],
	'basedir=s' => \$basedirs[0],
	'basedir1=s' => \$basedirs[0],
	'basedir2=s' => \$basedirs[1],
	'vardir=s' => \$vardirs[0],
	'vardir1=s' => \$vardirs[0],
	'vardir2=s' => \$vardirs[1],
	'rpl_mode=s' => \$rpl_mode,
	'engine=s' => \$engine,
	'grammar=s' => \$grammar_file,
	'skip-recursive-rules' => \$skip_recursive_rules,
	'redefine=s' => \$redefine_file,
	'threads=i' => \$threads,
	'queries=s' => \$queries,
	'duration=i' => \$duration,
	'help' => \$help,
	'debug' => \$debug,
	'validators:s@' => \$validators,
    'transformers:s@' =>\$transformers,
	'reporters:s@' => \$reporters,
	'report-xml-tt' => \$report_xml_tt,
	'report-xml-tt-type=s' => \$report_xml_tt_type,
	'report-xml-tt-dest=s' => \$report_xml_tt_dest,
	'gendata:s' => \$gendata,
	'skip-gendata' => \$skip_gendata,
	'notnull' => \$notnull,
	'short_column_names' => \$short_column_names,
	'strict_fields' => \$strict_fields,
	'freeze_time' => \$freeze_time,
	'seed=s' => \$seed,
	'mask=i' => \$mask,
    'mask-level=i' => \$mask_level,
	'no-mask' => \$no_mask,
	'mem' => \$mem,
	'rows=s' => \$rows,
	'varchar-length=i' => \$varchar_len,
	'xml-output=s'	=> \$xml_output,
	'valgrind'	=> \$valgrind,
	'valgrind-xml'	=> \$valgrind_xml,
	'views:s'	=> \$views,
	'sqltrace:s' => \$sqltrace,
	'start-dirty'	=> \$start_dirty,
	'filter=s'	=> \$filter,
    'mtr-build-thread=i' => \$build_thread,
    'testname=s' => \$testname,
	'lcov' => \$lcov,
    'logfile=s' => \$logfile,
    'logconf=s' => \$logconf,
    'report-tt-logdir=s' => \$report_tt_logdir,
    'querytimeout=i' => \$querytimeout
);

if (defined $logfile && defined $logger) {
    setLoggingToFile($logfile);
} else {
    if (defined $logconf && defined $logger) {
        setLogConf($logconf);
    }
}

$ENV{RQG_DEBUG} = 1 if defined $debug;

$validators = join(',', @$validators) if defined $validators;
$reporters = join(',', @$reporters) if defined $reporters;
$transformers = join(',', @$transformers) if defined $transformers;

if (!$opt_result) {
	exit(1);
} elsif ($help) {
	help();
	exit(0);
} elsif ($basedirs[0] eq '') {
	say("No basedir provided via --basedir.");
	exit(0);
} elsif (not defined $grammar_file) {
	say("No grammar file provided via --grammar");
	exit(0);
}

# --sqltrace may have a string value (optional).
# Allowed values for --sqltrace:
my %sqltrace_legal_values = (
    'MarkErrors' => 1 # Prefixes invalid SQL statements for easier post-processing
);

# If no value is given, GetOpt will assign the value '' (empty string).
if (length($sqltrace) > 0) {
    # A value is given, check if it is legal.
    if (not exists $sqltrace_legal_values{$sqltrace}) {
        say("Invalid value for --sqltrace option: '$sqltrace'");
        say("Valid values are: ".join(', ', keys(%sqltrace_legal_values)));
        say("No value means that default/plain sqltrace will be used.");
        exit(STATUS_ENVIRONMENT_FAILURE);
    }
}

say("Copyright (c) 2008,2011 Oracle and/or its affiliates. All rights reserved. Use is subject to license terms.");
say("Please see http://forge.mysql.com/wiki/Category:RandomQueryGenerator for more information on this test framework.");
say("Starting: $0 ".join(" ", @ARGV_saved));

#
# Calculate master and slave ports based on MTR_BUILD_THREAD (MTR
# Version 1 behaviour)
#

if (not defined $build_thread) {
    if (defined $ENV{MTR_BUILD_THREAD}) {
        $build_thread = $ENV{MTR_BUILD_THREAD}
    } else {
        $build_thread = DEFAULT_MTR_BUILD_THREAD;
    }
}

if ( $build_thread eq 'auto' ) {
    say ("Please set the environment variable MTR_BUILD_THREAD to a value <> 'auto' (recommended) or unset it (will take the value ".DEFAULT_MTR_BUILD_THREAD.") ");
    exit (STATUS_ENVIRONMENT_FAILURE);
}

my $master_port = 10000 + 10 * $build_thread;
my $slave_port = 10000 + 10 * $build_thread + 2;
my @master_ports = ($master_port,$slave_port);

say("master_port : $master_port slave_port : $slave_port master_ports : @master_ports MTR_BUILD_THREAD : $build_thread ");

$ENV{MTR_BUILD_THREAD} = $build_thread;

#
# If the user has provided two vardirs and one basedir, start second
# server using the same basedir
#

if (
	($vardirs[1] ne '') &&
	($basedirs[1] eq '')
) {
	$basedirs[1] = $basedirs[0];
}

foreach my $dir (cwd(), @basedirs) {
# calling bzr usually takes a few seconds...
    if (defined $dir) {
        my $bzrinfo = GenTest::BzrInfo->new(
            dir => $dir
            );
        my $revno = $bzrinfo->bzrRevno();
        my $revid = $bzrinfo->bzrRevisionId();

        if ((defined $revno) && (defined $revid)) {
            say("$dir Revno: $revno");
            say("$dir Revision-Id: $revid");
        } else {
            say($dir.' does not look like a bzr branch, cannot get revision info.');
        }
    }
}

if (
	($mysqld_options[1] ne '') &&
	($basedirs[1] eq '')
) {
	$basedirs[1] = $basedirs[0];
}

#
# If the user has provided identical basedirs and vardirs, warn of a potential overlap.
#

if (
	($basedirs[0] eq $basedirs[1]) &&
	($vardirs[0] eq $vardirs[1]) &&
	($rpl_mode eq '')
) {
	die("Please specify either different --basedir[12] or different --vardir[12] in order to start two MySQL servers");
}

#
# If RQG_HOME is set, prepend it to config files if they can not be found without it
#

$gendata = $ENV{RQG_HOME}.'/'.$gendata if defined $gendata && defined $ENV{RQG_HOME} && ! -e $gendata;
$grammar_file = $ENV{RQG_HOME}.'/'.$grammar_file if defined $grammar_file && defined $ENV{RQG_HOME} && ! -e $grammar_file;
$redefine_file = $ENV{RQG_HOME}.'/'.$redefine_file if defined $redefine_file && defined $ENV{RQG_HOME} && ! -e $redefine_file;

my $cwd = cwd();

if ($lcov) {
	unlink(tmpdir()."/lcov-rqg.info");
	system("lcov --directory $basedirs[0] --zerocounters");
}

#
# Start servers. Use rpl_alter if replication is needed.
#

foreach my $server_id (0..1) {
	next if $basedirs[$server_id] eq '';

	if (
		($server_id == 0) ||
		($rpl_mode eq '')
	) {
		$master_dsns[$server_id] = "dbi:mysql:host=127.0.0.1:port=".$master_ports[$server_id].":user=root:database=".$database;
	}

	my @mtr_options;
	push @mtr_options, lc("--mysqld=--$engine") if defined $engine && $engine !~ m{myisam|memory|heap|aria}sio;

	push @mtr_options, "--mem" if defined $mem;
	if ((defined $valgrind) || (defined $valgrind_xml)) {
		push @mtr_options, "--valgrind";
		if (defined $valgrind_xml) {
			push @mtr_options, "--valgrind-option='--xml=yes'";
			if (defined $vardirs[$server_id]) {
				push @mtr_options, "--valgrind-option='--xml-file=".$vardirs[$server_id]."/log/valgrind.xml'";
			} else {
				push @mtr_options, "--valgrind-option='--xml-file=".$basedirs[$server_id]."/mysql-test/var/log/valgrind.xml'";
			}
		}
	}

	push @mtr_options, "--skip-ndb";
	push @mtr_options, "--mysqld=--core-file";
	push @mtr_options, "--mysqld=--loose-new";
	push @mtr_options, "--mysqld=--default-storage-engine=$engine" if defined $engine;
	push @mtr_options, "--mysqld=--sql-mode=no_engine_substitution" if join(' ', @ARGV_saved) !~ m{sql-mode}io;
	push @mtr_options, "--mysqld=--relay-log=slave-relay-bin";
	push @mtr_options, "--mysqld=--loose-innodb";
	push @mtr_options, "--mysqld=--loose-falcon-debug-mask=2";
	push @mtr_options, "--mysqld=--secure-file-priv=";		# Disable secure-file-priv that mtr enables.
	push @mtr_options, "--mysqld=--max-allowed-packet=16Mb";	# Allow loading bigger blobs
	push @mtr_options, "--mysqld=--loose-innodb-status-file=1";
	push @mtr_options, "--mysqld=--master-retry-count=65535";
	push @mtr_options, "--mysqld=--loose-debug-assert-if-crashed-table";
	push @mtr_options, "--mysqld=--loose-debug-assert-on-error";
	push @mtr_options, "--mysqld=--skip-name-resolve";

	push @mtr_options, "--start-dirty" if defined $start_dirty;
	push @mtr_options, "--gcov" if $lcov;

	if (($rpl_mode ne '') && ($server_id != 0)) {
		# If we are running in replication, and we start the slave separately (because it is a different binary)
		# add a few options that allow the slave and the master to be distinguished and SHOW SLAVE HOSTS to work
		push @mtr_options, "--mysqld=--server-id=".($server_id + 1);
		push @mtr_options, "--mysqld=--report-host=127.0.0.1";
		push @mtr_options, "--mysqld=--report-port=".$master_ports[$server_id];
	}

	my $mtr_path = $basedirs[$server_id].'/mysql-test/';
	chdir($mtr_path) or croak "unable to chdir() to $mtr_path: $!";

	push @mtr_options, "--vardir=$vardirs[$server_id]" if defined $vardirs[$server_id];
	push @mtr_options, "--master_port=".$master_ports[$server_id];

	if (defined $mysqld_options[$server_id]) {
		foreach my $mysqld_option (@{$mysqld_options[$server_id]}) {
			push @mtr_options, '--mysqld="'.$mysqld_option.'"';
		}
	}

	if (
		($rpl_mode ne '') &&
		($server_id == 0) &&
		(not defined $vardirs[1]) &&
		(not defined $mysqld_options[1])
	) {
		push @mtr_options, 'rpl_alter';
		push @mtr_options, "--slave_port=".$slave_port;
	} elsif ($basedirs[$server_id] =~ m{(^|[-/ ])5\.0}sgio) {
		say("Basedir implies server version 5.0. Will not use --start-and-exit 1st");
		# Do nothing, test name "1st" does not exist in 5.0
	} else {
		push @mtr_options, '1st';
	}

	$ENV{MTR_VERSION} = 1;
#	my $out_file = "/tmp/mtr-".$$."-".$server_id.".out";
	my $mtr_command = "perl mysql-test-run.pl --start-and-exit ".join(' ', @mtr_options)." 2>&1";
	say("Running $mtr_command .");

	my $vardir = $vardirs[$server_id] || $basedirs[$server_id].'/mysql-test/var';

	open (MTR_COMMAND, '>'.$mtr_path.'/mtr_command') or say("Unable to open mtr_command: $!");
	print MTR_COMMAND $mtr_command;
	close MTR_COMMAND;

	my $mtr_status = system($mtr_command);

	if ($mtr_status != 0) {
#		system("cat $out_file");
		system("cat \"$vardir/log/master.err\"");
		exit_test(STATUS_ENVIRONMENT_FAILURE);
	}
#	unlink($out_file);

	if ((defined $master_dsns[$server_id]) && (defined $engine)) {
		my $dbh = DBI->connect($master_dsns[$server_id], undef, undef, { RaiseError => 1 } );
		$dbh->do("SET GLOBAL storage_engine = '$engine'");
	}
}

chdir($cwd);

my $master_dbh = DBI->connect($master_dsns[0], undef, undef, { RaiseError => 1 } );

if ($rpl_mode) {
	my $slave_dsn = "dbi:mysql:host=127.0.0.1:port=".$slave_port.":user=root:database=".$database;
	my $slave_dbh = DBI->connect($slave_dsn, undef, undef, { RaiseError => 1 } );

	say("Establishing replication, mode $rpl_mode ...");

	my ($foo, $master_version) = $master_dbh->selectrow_array("SHOW VARIABLES LIKE 'version'");

	if (($master_version !~ m{^5\.0}sio) && ($rpl_mode ne 'default')) {
		$master_dbh->do("SET GLOBAL BINLOG_FORMAT = '$rpl_mode'");
		$slave_dbh->do("SET GLOBAL BINLOG_FORMAT = '$rpl_mode'");
	}

	$slave_dbh->do("STOP SLAVE");

	$slave_dbh->do("SET GLOBAL storage_engine = '$engine'") if defined $engine;

	$slave_dbh->do("CHANGE MASTER TO
		MASTER_PORT = $master_ports[0],
		MASTER_HOST = '127.0.0.1',
               MASTER_USER = 'root',
               MASTER_CONNECT_RETRY = 1
	");

	$slave_dbh->do("START SLAVE");
}

#
# Run actual queries
#

my @gentest_options;

push @gentest_options, "--start-dirty" if defined $start_dirty;
push @gentest_options, "--gendata=$gendata" if not defined $skip_gendata;
push @gentest_options, "--notnull" if defined $notnull;
push @gentest_options, "--short_column_names" if defined $short_column_names;
push @gentest_options, "--strict_fields" if defined $strict_fields;
push @gentest_options, "--freeze_time" if defined $freeze_time;
push @gentest_options, "--engine=$engine" if defined $engine;
push @gentest_options, "--rpl_mode=$rpl_mode" if defined $rpl_mode;
push @gentest_options, map {'--validator='.$_} split(/,/,$validators) if defined $validators;
push @gentest_options, map {'--reporter='.$_} split(/,/,$reporters) if defined $reporters;
push @gentest_options, map {'--transformer='.$_} split(/,/,$transformers) if defined $transformers;
push @gentest_options, "--threads=$threads" if defined $threads;
push @gentest_options, "--queries=$queries" if defined $queries;
push @gentest_options, "--duration=$duration" if defined $duration;
push @gentest_options, "--dsn=$master_dsns[0]" if defined $master_dsns[0];
push @gentest_options, "--dsn=$master_dsns[1]" if defined $master_dsns[1];
push @gentest_options, "--grammar=$grammar_file";
push @gentest_options, "--skip-recursive-rules" if defined $skip_recursive_rules;
push @gentest_options, "--redefine=$redefine_file" if defined $redefine_file;
push @gentest_options, "--seed=$seed" if defined $seed;
push @gentest_options, "--mask=$mask" if ((defined $mask) && (not defined $no_mask));
push @gentest_options, "--mask-level=$mask_level" if defined $mask_level;
push @gentest_options, "--rows=$rows" if defined $rows;
push @gentest_options, "--views=$views" if defined $views;
push @gentest_options, "--varchar-length=$varchar_len" if defined $varchar_len;
push @gentest_options, "--xml-output=$xml_output" if defined $xml_output;
push @gentest_options, "--report-xml-tt" if defined $report_xml_tt;
push @gentest_options, "--report-xml-tt-type=$report_xml_tt_type" if defined $report_xml_tt_type;
push @gentest_options, "--report-xml-tt-dest=$report_xml_tt_dest" if defined $report_xml_tt_dest;
push @gentest_options, "--debug" if defined $debug;
push @gentest_options, "--filter=$filter" if defined $filter;
push @gentest_options, "--valgrind" if defined $valgrind;
push @gentest_options, "--valgrind-xml" if defined $valgrind_xml;
push @gentest_options, "--testname=$testname" if defined $testname;
push @gentest_options, "--sqltrace".(length($sqltrace)>0 ? "=$sqltrace" : '' ) if defined $sqltrace;
push @gentest_options, "--logfile=$logfile" if defined $logfile;
push @gentest_options, "--logconf=$logconf" if defined $logconf;
push @gentest_options, "--report-tt-logdir=$report_tt_logdir" if defined $report_tt_logdir;
push @gentest_options, "--querytimeout=$querytimeout" if defined $querytimeout;

# Push the number of "worker" threads into the environment.
# lib/GenTest/Generator/FromGrammar.pm will generate a corresponding grammar element.
$ENV{RQG_THREADS}= $threads;

my $gentest_result = system("perl ".($Carp::Verbose?"-MCarp=verbose ":"").
                            "$ENV{RQG_HOME}gentest.pl ".join(' ', @gentest_options)) >> 8;
say("gentest.pl exited with exit status ".status2text($gentest_result). " ($gentest_result)");

if ($lcov) {
	say("Trying to generate a genhtml lcov report in ".tmpdir()."/rqg-lcov-$$ ...");
	system("lcov --quiet --directory $basedirs[0] --capture --output-file ".tmpdir()."/lcov-rqg.info");
	system("genhtml --quiet --no-sort --output-directory=".tmpdir()."/rqg-lcov-$$ ".tmpdir()."/lcov-rqg.info");
	say("genhtml lcov report may have been generated in ".tmpdir()."/rqg-lcov-$$ .");

}

exit_test($gentest_result);

sub help {

	print <<EOF
Copyright (c) 2008,2011 Oracle and/or its affiliates. All rights reserved. Use is subject to license terms.

$0 - Run a complete random query generation test, including server start with replication and master/slave verification

    Options related to one standalone MySQL server:

    --basedir   : Specifies the base directory of the stand-alone MySQL installation;
    --mysqld    : Options passed to the MySQL server
    --vardir    : Optional. (default \$basedir/mysql-test/var);

    Options related to two MySQL servers

    --basedir1  : Specifies the base directory of the first MySQL installation;
    --basedir2  : Specifies the base directory of the second MySQL installation;
    --mysqld1   : Options passed to the first MySQL server
    --mysqld2   : Options passed to the second MySQL server
    --vardir1   : Optional. (default \$basedir1/mysql-test/var);
    --vardir2   : Optional. (default \$basedir2/mysql-test/var);

    General options

    --grammar   : Grammar file to use when generating queries (REQUIRED);
    --redefine  : Grammar file to redefine and/or add rules to the given grammar
    --rpl_mode  : Replication type to use (statement|row|mixed) (default: no replication);
    --vardir1   : Optional.
    --vardir2   : Optional.
    --engine    : Table engine to use when creating tables with gendata (default no ENGINE in CREATE TABLE);
    --threads   : Number of threads to spawn (default $default_threads);
    --queries   : Number of queries to execute per thread (default $default_queries);
    --duration  : Duration of the test in seconds (default $default_duration seconds);
    --validator : The validators to use
    --reporter  : The reporters to use
    --transformer: The transformers to use (turns on --validator=transformer). Accepts comma separated list
    --querytimeout: The timeout to use for the QueryTimeout reporter
    --gendata   : Generate data option. Passed to gentest.pl
    --seed      : PRNG seed. Passed to gentest.pl
    --mask      : Grammar mask. Passed to gentest.pl
    --mask-level: Grammar mask level. Passed to gentest.pl
    --rows      : No of rows. Passed to gentest.pl
    --varchar-length: length of strings. passed to gentest.pl
    --xml-output: Passed to gentest.pl
    --report-xml-tt: Passed to gentest.pl
    --report-xml-tt-type: Passed to gentest.pl
    --report-xml-tt-dest: Passed to gentest.pl
    --testname  : Name of test, used for reporting purposes
    --sqltrace  : Print all generated SQL statements.
                  Optional: Specify --sqltrace=MarkErrors to mark invalid statements.
    --views     : Generate views. Optionally specify view type (algorithm) as option value. Passed to gentest.pl
    --valgrind  : Passed to gentest.pl
    --filter    : Passed to gentest.pl
    --mem       : Passed to mtr
    --mtr-build-thread: Value used for MTR_BUILD_THREAD when servers are started and accessed
    --short_column_names: Use short column names in gendata (c<number>)
    --strict_fields: Disable all AI applied to columns defined in \$fields in the gendata file. Allows for very specific column definitions
    --freeze_time: Freeze time for each query so that CURRENT_TIMESTAMP gives the same result for all transformers/validators
    --debug     : Debug mode
    --help      : This help message

    If you specify --basedir1 and --basedir2 or --vardir1 and --vardir2, two servers will be started and the results from the queries
    will be compared between them.
EOF
	;
	print "$0 arguments were: ".join(' ', @ARGV_saved)."\n";
	exit_test(STATUS_UNKNOWN_ERROR);
}

sub exit_test {
	my $status = shift;

	print isoTimestamp()." [$$] $0 will exit with exit status ".status2text($status)." ($status)\n";
	safe_exit($status);
}


#!/usr/bin/perl

# Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
# Use is subject to license terms.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA

#################### FOR THE MOMENT THIS SCRIPT IS FOR TESTING PURPOSES

use lib 'lib','lib/DBServer';
use lib "$ENV{RQG_HOME}/lib";
use Carp;
use strict;
use DBServer::DBServer;
use DBServer::MySQL::MySQLd;
use DBServer::MySQL::ReplMySQLd;

$| = 1;
if (osWindows()) {
	$SIG{CHLD} = "IGNORE";
}

if (defined $ENV{RQG_HOME}) {
    if (osWindows()) {
        $ENV{RQG_HOME} = $ENV{RQG_HOME}.'\\';
    } else {
        $ENV{RQG_HOME} = $ENV{RQG_HOME}.'/';
    }
}

use Getopt::Long;
use GenTest::Constants;
use DBI;
use Cwd;

my $database = 'test';
my @dsns;

my ($gendata, @basedirs, @mysqld_options, @vardirs, $rpl_mode,
    $engine, $help, $debug, $sourcedir,
    $valgrind, @valgrind_options,
    $start_dirty, $build_thread,$just_install);

my @ARGV_saved = @ARGV;

my $opt_result = GetOptions(
	'mysqld=s@' => \$mysqld_options[0],
	'mysqld1=s@' => \$mysqld_options[0],
	'mysqld2=s@' => \$mysqld_options[1],
    'basedir=s' => \$basedirs[0],
    'basedir1=s' => \$basedirs[0],
    'basedir2=s' => \$basedirs[1],
    'sourcedir=s' => \$sourcedir,
	#'basedir=s@' => \@basedirs,
	'vardir=s' => \$vardirs[0],
	'vardir1=s' => \$vardirs[0],
	'vardir2=s' => \$vardirs[1],
	#'vardir=s@' => \@vardirs,
	'rpl_mode=s' => \$rpl_mode,
	'engine=s' => \$engine,
	'help' => \$help,
	'debug' => \$debug,
	'valgrind!'	=> \$valgrind,
	'valgrind_options=s@'	=> \@valgrind_options,
	'start-dirty'	=> \$start_dirty,
    'mtr-build-thread=i' => \$build_thread,
    'just-install' => \$just_install
    );

if (!$opt_result || $help || $basedirs[0] eq '') {
	help();
	exit($help ? 0 : 1);
}

say("Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. Use is subject to license terms.");
say("Please see http://forge.mysql.com/wiki/Category:RandomQueryGenerator for more information on this test framework.");
say("Starting \n# $0 \\ \n# ".join(" \\ \n# ", @ARGV_saved));

#
# Calculate master and slave ports based on MTR_BUILD_THREAD (MTR
# Version 1 behaviour)
#

if (not defined $build_thread) {
    if (defined $ENV{MTR_BUILD_THREAD}) {
        $build_thread = $ENV{MTR_BUILD_THREAD}
    } else {
        $build_thread = DEFAULT_MTR_BUILD_THREAD;
    }
}

if ( $build_thread eq 'auto' ) {
    say ("Please set the environment variable MTR_BUILD_THREAD to a value <> 'auto' (recommended) or unset it (will take the value ".DEFAULT_MTR_BUILD_THREAD.") ");
    exit (STATUS_ENVIRONMENT_FAILURE);
}

my @ports = (10000 + 10 * $build_thread, 10000 + 10 * $build_thread + 2);

say("master_port : $ports[0] slave_port : $ports[1] ports : @ports MTR_BUILD_THREAD : $build_thread ") if !$just_install;

#
# If the user has provided two vardirs and one basedir, start second
# server using the same basedir
#

if (
	($vardirs[1] ne '') &&
	($basedirs[1] eq '')
    ) {
	$basedirs[1] = $basedirs[0];
}

if (
	($mysqld_options[1] ne '') &&
	($basedirs[1] eq '')
    ) {
	$basedirs[1] = $basedirs[0];
}

#
# If the user has provided identical basedirs and vardirs, warn of a
# potential overlap.
#

if (
	($basedirs[0] eq $basedirs[1]) &&
	($vardirs[0] eq $vardirs[1]) &&
	($rpl_mode eq '')
    ) {
	croak("Please specify either different --basedir[12] or different --vardir[12] in order to start two MySQL servers");
}

#
# Start servers. Use rpl_alter if replication is needed.
#

my @server;
my $rplsrv;

if ($rpl_mode ne '') {
    my @options;
    push @options, lc("--$engine") if defined $engine && lc($engine) ne lc('myisam');

    push @options, "--sql-mode=no_engine_substitution" if join(' ', @ARGV_saved) !~ m{sql-mode}io;

    if (defined $mysqld_options[0]) {
        push @options, @{$mysqld_options[0]};
    }

    $rplsrv = DBServer::MySQL::ReplMySQLd->new(basedir => $basedirs[0],
                                               master_vardir => $vardirs[0],
                                               master_port => $ports[0],
                                               slave_vardir => $vardirs[1],
                                               slave_port => $ports[1],
                                               mode => $rpl_mode,
                                               server_options => \@options,
                                               valgrind => $valgrind,
                                               valgrind_options => \@valgrind_options,
                                               start_dirty => $start_dirty);

    if (!$just_install) {
        my $status = $rplsrv->startServer();

        if ($status > STATUS_OK) {
            stopServers();
            say(system("ls -l ".$rplsrv->master->datadir));
            say(system("ls -l ".$rplsrv->slave->datadir));
            croak("Could not start replicating server pair");
        }

        $dsns[0] = $rplsrv->master->dsn($database);
        $dsns[1] = undef; ## passed to gentest. No dsn for slave!
        $server[0] = $rplsrv->master;
        $server[1] = $rplsrv->slave;
    }

} else {
    if ($#basedirs != $#vardirs) {
        croak ("The number of basedirs and vardirs must match $#basedirs != $#vardirs")
    }
    foreach my $server_id (0..1) {
        next if $basedirs[$server_id] eq '';

        my @options;
        push @options, lc("--$engine") if defined $engine && lc($engine) ne lc('myisam');

        push @options, "--sql-mode=no_engine_substitution" if join(' ', @ARGV_saved) !~ m{sql-mode}io;

        if (defined $mysqld_options[$server_id]) {
            push @options, @{$mysqld_options[$server_id]};
        }

        $server[$server_id] = DBServer::MySQL::MySQLd->new(basedir => $basedirs[$server_id],
                                                           sourcedir => $sourcedir,
                                                           vardir => $vardirs[$server_id],
                                                           port => $ports[$server_id],
                                                           start_dirty => $start_dirty,
                                                           valgrind => $valgrind,
                                                           valgrind_options => \@valgrind_options,
                                                           server_options => \@options);

        if (!$just_install) {
            my $status = $server[$server_id]->startServer;

            if ($status > STATUS_OK) {
                stopServers();
                say(system("ls -l ".$server[$server_id]->datadir));
                croak("Could not start all servers");
            }

            if (
                ($server_id == 0) ||
                ($rpl_mode eq '')
                ) {
                $dsns[$server_id] = $server[$server_id]->dsn($database);
            }

            if ((defined $dsns[$server_id]) && (defined $engine)) {
                my $dbh = DBI->connect($dsns[$server_id], undef, undef, { RaiseError => 1 } );
                $dbh->do("SET GLOBAL storage_engine = '$engine'");
            }
        }
    }
}

if (!$just_install) {
    say("\n\nHit return to stop server(s)");

    my $something = <STDIN>;

    stopServers();

    sub stopServers {
        if ($rpl_mode ne '') {
            $rplsrv->stopServer();
        } else {
            foreach my $srv (@server) {
                if ($srv) {
                    $srv->stopServer;
                }
            }
        }
    }

}

sub help {

	print <<EOF
Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. Use is subject to license terms.

$0 - Run a complete random query generation test, including server start with replication and master/slave verification

    Options related to one standalone MySQL server:

    --basedir   : Specifies the base directory of the stand-alone MySQL installation;
    --mysqld    : Options passed to the MySQL server
    --vardir    : Optional. (default \$basedir/mysql-test/var);

    Options related to two MySQL servers

    --basedir1  : Specifies the base directory of the first MySQL installation;
    --basedir2  : Specifies the base directory of the second MySQL installation;
    --mysqld1   : Options passed to the first MySQL server
    --mysqld2   : Options passed to the second MySQL server
    --vardir1   : Optional. (default \$basedir1/mysql-test/var);
    --vardir2   : Optional. (default \$basedir2/mysql-test/var);

    General options

    --just-install: Just create the database(s) (mysql_install_db), don't start the server
    --grammar   : Grammar file to use when generating queries (REQUIRED);
    --redefine  : Grammar file to redefine and/or add rules to the given grammar
    --rpl_mode  : Replication type to use (statement|row|mixed) (default: no replication);
    --vardir1   : Optional.
    --vardir2   : Optional.
    --engine    : Table engine to use when creating tables with gendata (default no ENGINE in CREATE TABLE);
    --valgrind  : Passed to gentest.pl
    --mtr-build-thread:
                  Value used for MTR_BUILD_THREAD when servers are started and accessed.
    --debug     : Debug mode
    --help      : This help message

    If you specify --basedir1 and --basedir2 or --vardir1 and --vardir2, two servers will be started and the results from the queries
    will be compared between them.
EOF
	;
	print "$0 arguments were: ".join(' ', @ARGV_saved)."\n";
	exit_test(STATUS_UNKNOWN_ERROR);
}

sub exit_test {
	my $status = shift;
    stopServers();
	say("[$$] $0 will exit with exit status $status");
	safe_exit($status);
}


use strict;

$| = 1;

use lib 'lib';
use GenTest::SimPipe::Testcase;
use GenTest::SimPipe::Oracle::Crash;
use GenTest;
use GenTest::Constants;
use GenTest::Executor::MySQL;
use DBI;
use Data::Dumper;

my $test = 'case.test';
open (Q, $test) or die $!;

my $dsn = 'dbi:mysql:port=19300:user=root:host=127.0.0.1:database=test';
my $oracle = GenTest::SimPipe::Oracle::Crash->new( dsn => $dsn , basedir => '/home/philips/bzr/maria-5.3' );
$oracle->startServer();

my $dbh = DBI->connect($dsn, undef, undef, { mysql_multi_statements => 1, PrintError => 1 });
$dbh->do("DROP DATABASE IF EXISTS test; CREATE DATABASE test; USE test");

while (<Q>) {
	chomp;
	next if $_ eq '';
	$_ =~ s{SESSION}{GLOBAL}sgio;
	$_ =~ s{INSERT}{INSERT IGNORE}sgio;
	$dbh->do($_);
}

my $testcase = GenTest::SimPipe::Testcase->newFromDSN( $dsn, [
	"SELECT 1 FROM DUAL"
]);

my $new_testcase = $testcase->simplify($oracle);

print $new_testcase->toString();


use strict;

$| = 1;

use lib 'lib';
use GenTest::SimPipe::Testcase;
use GenTest::SimPipe::Oracle::FullScan;
use GenTest;
use GenTest::Constants;
use GenTest::Executor::MySQL;
use DBI;
use Data::Dumper;

my $dsn = 'dbi:mysql:port=9306:user=root:host=127.0.0.1:database=test';
my $oracle = GenTest::SimPipe::Oracle::FullScan->new(
	dsn => $dsn,
	basedir => '/home/philips/bzr/maria-5.3'
);

my $dbh = DBI->connect($dsn, undef, undef, { mysql_multi_statements => 1, RaiseError => 1 });

my $query = " SELECT 1 FROM DUAL ";

$dbh->do("USE test");
$dbh->do("SET SQL_MODE='NO_ENGINE_SUBSTITUTION'");

my $test = 'case.test';
open (Q, $test) or die $!;
read (Q, my $sql, -s $test);
$test =~ s{LOCAL}{GLOBAL}sgio;

$dbh->do($sql);
my $testcase = GenTest::SimPipe::Testcase->newFromDBH($dbh, [ $query ]);

my $new_testcase = $testcase->simplify($oracle);

print $new_testcase->toString();


use strict;

$| = 1;

use lib 'lib';
use GenTest::SimPipe::Testcase;
use GenTest::SimPipe::Oracle::FullScan;
use GenTest;
use GenTest::Constants;
use GenTest::Executor::MySQL;
use DBI;
use Data::Dumper;

my $dsn = 'dbi:mysql:port=9306:user=root:host=127.0.0.1:database=test';
my $oracle = GenTest::SimPipe::Oracle::FullScan->new( dsn => $dsn , basedir => '/home/philips/bzr/maria-5.3' );

my $dbh = DBI->connect($dsn, undef, undef, { mysql_multi_statements => 1, RaiseError => 1 });

my $query = "
SELECT alias2.col_datetime_key AS field1 , alias2.pk AS field2
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.pk = alias1.col_int_key AND alias2.pk != alias1.col_varchar_key
GROUP BY field1 , field2
ORDER BY alias1.col_int_key , field2;";

$dbh->do("USE test");

my $test = '/home/philips/bzr/randgen-simpipe/case.test';
open (Q, $test) or die $!;
read (Q, my $sql, -s $test);

$dbh->do($sql);
my $testcase = GenTest::SimPipe::Testcase->newFromDBH($dbh, [ $query ]);

my $new_testcase = $testcase->simplify($oracle);

print $new_testcase->toString();


# Copyright (C) 2009 Sun Microsystems, Inc. All rights reserved.  Use
# is subject to license terms.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA

#!/usr/bin/perl

use lib 'lib';
use lib "$ENV{RQG_HOME}/lib";
use strict;
use GenTest;
use GenTest::Translator;
use GenTest::Translator::MysqlDML2ANSI;
use GenTest::Translator::MysqlDML2pgsql;
use GenTest::Translator::MysqlDML2javadb;
use GenTest::Translator::Mysqldump2ANSI;
use GenTest::Translator::Mysqldump2pgsql;
use GenTest::Translator::Mysqldump2javadb;

use Getopt::Long;

my $from = "unspecified";
my $to = "ansi";

my $opt_result = GetOptions(
    'from=s' => $from,
    'to=s' => \$to
    );

$from =~ tr/A-Z/a-z/;
$to =~ tr/A-Z/a-z/;

my $translator1;
my $translator2;
if ($to eq "ansi") {
    $translator1 = GenTest::Translator::Mysqldump2ANSI->new();
    $translator2 = GenTest::Translator::MysqlDML2ANSI->new();
} elsif ($to eq "javadb" || $to eq "derby") {
    $translator1 = GenTest::Translator::Mysqldump2javadb->new();
    $translator2 = GenTest::Translator::MysqlDML2javadb->new();
} elsif ($to eq "postgres" || $to eq "pg" || $to eq "postgresql" || $to eq "pgsql") {
    $translator1 = GenTest::Translator::Mysqldump2pgsql->new();
    $translator2 = GenTest::Translator::MysqlDML2pgsql->new();
} else {
    die "Unknown target \"$to\", use \"ansi\", \"javadb\" or \"postgresql\"";
}

my $file;
while(<>) {
    $file .= $_;
}

my $result;

if ($from eq "unspecified") {
    $result = $translator1->translate($file);
    $result = $translator2->translate($result);
} elsif ($from eq "mysqldump") {
    $result = $translator1->translate($file);
} elsif ($from eq "dml") {
    $result = $translator2->translate($file);
} else {
    die "Unknown source \"$from\", if specified, use \"mysqldump\" or \"dml\"";
}

print $result;


# Copyright (C) 2009 Sun Microsystems, Inc. All rights reserved.  Use
# is subject to license terms.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA

use lib 'lib';

use GenTest;
use GenTest::Executor;
use GenTest::App::Gendata;
use GenTest::Grammar;
use GenTest::Generator::FromGrammar;
use Time::HiRes;

my $arg = shift;

if ($arg eq 'grammar') {
########################################
    say("Benchmark $arg: FromGrammar->next()");

    my $grammar = GenTest::Grammar->new(grammar_file => 'bench/WL5004_sql.yy');

    my $generator = GenTest::Generator::FromGrammar->new(grammar => $grammar,
                                                         seed => 0);

    my $executor = GenTest::Executor->newFromDSN("dummy");
    $executor->init();
    $executor->cacheMetaData();

    my $start = Time::HiRes::time();
    foreach $i (0..50000) {
    $generator->next([$executor,undef]);
    }
    my $stop = Time::HiRes::time();
    open TM,">bench/grammar.dat";
    print TM "YVALUE = ".($stop - $start)."\n";
    close TM;

} elsif ($arg eq 'gendata') {
########################################
    say("benchmark $arg: Gendata->run()");

    my $gen = GenTest::App::Gendata->new(dsn => "dummy",
                                         spec_file => "bench/falcon_data_types.zz",
                                         rows => 5000,
                                         views => 1);

    my $start = Time::HiRes::time();
    my $status = $gen->run();
    my $stop = Time::HiRes::time();

    open TM,">bench/gendata.dat";
    print TM "YVALUE = ".($stop - $start)."\n";
    close TM;
} else {
    foreach my $b ('gendata','grammar') {
        say("----------------------------------------------");
        system("perl -d:DProf bench/benchmark.pl $b");
        say("Collecting profiling information");
        system("dprofpp -u");
    }
}


# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA

# This script can be used to load the files from
# http://www.tm.kit.edu/~mayer/osm2wkt/
# into MySQL and PostGIS

use strict;

print '
/*

@MISC{mayer2010osm,
  author = {Christoph P. Mayer},
  title = {osm2wkt - OpenStreetMap to WKT Conversion},
  howpublished = {http://www.tm.kit.edu/~mayer/osm2wkt},
  year = {2010}
}

Map data (c) OpenStreetMap contributors, CC-BY-SA

*/'."\n";

print "DROP TABLE IF EXISTS linestring;\n";

if ($ARGV[0] eq 'MySQL') {
	print "CREATE TABLE linestring (pk INTEGER NOT NULL PRIMARY KEY, linestring_key GEOMETRY NOT NULL, linestring_nokey GEOMETRY NOT NULL) ENGINE=Aria TRANSACTIONAL=0;\n";
} elsif ($ARGV[0] eq 'PostGIS') {
	print "CREATE TABLE linestring (pk INTEGER NOT NULL PRIMARY KEY);\n";
	print "SELECT AddGeometryColumn('linestring', 'linestring_key', -1, 'GEOMETRY', 2 );\n";
	print "SELECT AddGeometryColumn('linestring', 'linestring_nokey', -1, 'GEOMETRY', 2 );\n";
}

my $counter = 1;
while (<STDIN>) {
	chomp $_;
	print "INSERT INTO linestring (pk, linestring_key, linestring_nokey) VALUES ($counter, GeomFromText('$_'), GeomFromText('$_'));\n";
	$counter++;
}

if ($ARGV[0] eq 'MySQL') {
	print "ALTER TABLE linestring ADD SPATIAL KEY (linestring_key);\n";
} elsif ($ARGV[0] eq 'MySQL')  {
	print "CREATE INDEX linestring_index ON linestring USING GIST ( linestring_key );\n";
}


use strict;
use DBI;
$| = 1;

my $osm_dbi = 'dbi:mysql:user=root:database=osm';
my $oqg_dbi = 'dbi:mysql:host=127.0.0.1:port=9306:database=test:user=root';

my $osm_dbh = DBI->connect($osm_dbi, undef , undef , { RaiseError => 1});
my $oqg_dbh = DBI->connect($oqg_dbi, undef , undef , { RaiseError => 1});

my $ways = $osm_dbh->selectcol_arrayref("SELECT DISTINCT id FROM ways");

$oqg_dbh->do("CREATE TABLE IF NOT EXISTS osm (    latch   SMALLINT  UNSIGNED NULL,    origid  BIGINT    UNSIGNED NULL,    destid  BIGINT    UNSIGNED NULL,    weight  DOUBLE    NULL,    seq     BIGINT    UNSIGNED NULL,    linkid  BIGINT    UNSIGNED NULL,    KEY (latch, origid, destid) USING HASH,    KEY (latch, destid, origid) USING HASH  ) ENGINE=OQGRAPH");

print "$#$ways found.\n";

foreach my $way (@$ways) {
	my $nodes = $osm_dbh->selectcol_arrayref("SELECT node_id FROM way_nodes WHERE id = $way ORDER BY sequence_id");
#	print "$#$nodes found for way $way\n";

	if ($#$nodes > 1) {
		$oqg_dbh->do("
			INSERT INTO osm ( origid, destid ) VALUES ".
			join(', ', map { "( $nodes->[$_] , $nodes->[$_ + 1] )" } (0..($#$nodes-1)))
		);
		print "*";
	} else {
		print ".";
	}
}


use strict;
use Data::Dumper;
use DBI;

my @php_files = @ARGV;
my %queries;

foreach my $php_file (@php_files) {
	open (FILE, $php_file) or die $!;
	read (FILE, my $php_code, -s $php_file) or die $!;
	close FILE;

	my @file_selects = $php_code =~ m{(SELECT.*?)'}sog;
	foreach my $file_select (@file_selects) {
		$file_select =~ s{\{db_prefix\}}{smf_}sgio;
		my ($trial_select , $grammar_select) = ($file_select , $file_select);

		$trial_select =~ s{(\{.*?\})}{1}sgio;

		$grammar_select =~ s{\{([a-z_]*?):[a-z_]*?\}}{_\1}sgio;
		$grammar_select =~ s{\{STEP_LOW\}}{_step_low}sgio;
		$grammar_select =~ s{\{STEP_HIGH\}}{_step_high}sgio;

		push @{$queries{'select'}} , [ $trial_select , $grammar_select ];
	}

	my @file_updates = $php_code =~  m{(UPDATE.*?)'}sog;
	foreach my $file_update (@file_updates) {
		$file_update =~ s{\{db_prefix\}}{smf_}sgio;
		my ($trial_update , $grammar_update) = ($file_update, $file_update);

		$trial_update =~ s{(\{.*?\})}{1}sgio;
		$grammar_update =~ s{\{([a-z_]*?):[a-z_]*?\}}{_\1}sgio;
		push @{$queries{'update'}} , [ $trial_update , $grammar_update ];
	}

	my @file_deletes = $php_code =~  m{(DELETE.*?)'}sog;
	foreach my $file_delete (@file_deletes) {
		$file_delete =~ s{\{db_prefix\}}{smf_}sgio;
		my ($trial_delete , $grammar_delete) = ($file_delete, $file_delete);

		$trial_delete =~ s{(\{.*?\})}{1}sgio;
		$grammar_delete =~ s{\{([a-z_]*?):[a-z_]*?\}}{_\1}sgio;
		push @{$queries{'delete'}} , [ $trial_delete , $grammar_delete ];
	}

	my @file_insertsphp = $php_code =~ m{'db_insert']\((.*?)\);}sgio;
	my @file_inserts;

	foreach my $file_insertphp (@file_insertsphp) {
		$file_insertphp =~ s{[\r\n]}{}sgio;
		my ($insert_replace, $table) = $file_insertphp =~ m{'(.*?)'.*?'(.*?)'}sio;

		$insert_replace = 'insert '.$insert_replace if $insert_replace !~ m{^(insert|replace)}sgio;

		$table =~ s{\{db_prefix\}}{smf_}sgio;

		die $file_insertphp if $table eq '';
		my ($array) = $file_insertphp =~ m{array\((.*?)\)}sio;
		my @array_elements = split (',', $array);

		my @col_names;
		my @col_values;
		my @col_types;
		foreach my $array_element (@array_elements) {
			next if $array_element =~ m{^\s+$}sgio;
			my ($col_name, $col_type) = $array_element =~ m{'(.*?)'\s+=>\s+'(.*?)'}sio;
			my $col_value;
			$col_type =~ s{\-}{_}sgio;
			$col_type = "_".$col_type;
			if (defined $col_name) {
				$col_type eq 'unknown_type' if $col_type eq '';
				push @col_names, $col_name;
				push @col_values, 1;
				push @col_types, $col_type;
			}
		}

		if ($#col_names > -1) {
			push @{$queries{'insert_replace'}} , [
				 uc($insert_replace)." INTO $table (".join(',', @col_names).") VALUES (".join(',', @col_values).")",
				 uc($insert_replace)." INTO $table (".join(',', map {'`'.$_.'`' }@col_names).") VALUES (".join(',', @col_types).")"
			]
		}
	}
}

my $dbh = DBI->connect('dbi:mysql:database=smf2:user=root', undef , undef , { PrintError => 1});

my %errors;
print '
	query:
		insert_replace | insert_replace | insert_replace | insert_replace | insert_replace | insert_replace |
		update | update | update | update | update |
		delete |
		select | select | select ;

	_int: _mediumint_unsigned | _tinyint_unsigned | _digit ;
	_string: _english | _varchar(1) | _varchar(2) | _varchar(255) | REPEAT ( _varchar(2) , _tinyint_unsigned );
	_string_16: _english | _varchar(1) | _varchar(2) | _varchar(16) |  REPEAT ( _varchar(2) , _digit );
	_string_40: _english | _varchar(1) | _varchar(2) | _varchar(40) |  REPEAT ( _varchar(2) , _digit );
	_string_255: _english | _varchar(1) | _varchar(2) | _varchar(255) | REPEAT ( _varchar(2) , _tinyint_unsigned );
	_string_65534: _english | _varchar(1) | _varchar(2) | _varchar(255) | REPEAT ( _varchar(2) , _smallint_unsigned );
	_array_int: _int | _array_int , _int ;
	_array_string: _string | _string , _string ;
	_raw: _digit ;
	_step_low: _digit | _tinyint_unsigned ;
	_step_high: _tinyint_unsigned | _smallint_unsigned ;
';

foreach my $query_type ('select', 'insert_replace','update','delete') {
	my $type_queries = $queries{$query_type};
	my @type_rules;
	foreach my $type_query (@$type_queries) {
		my ($trial_query, $grammar_rule) = ($type_query->[0], $type_query->[1]);
		my $sth = $dbh->prepare($trial_query);
		$sth->execute();
		$errors{$sth->err()}++;

		if (($sth->err() == 0) || ($sth->err() == 1062)) {
			$grammar_rule =~ s{(data|next_time|time_offset|time_regularity|time_unit|time_updated|time_removed)}{`$1`}sgio;
			$grammar_rule =~ s{``}{`}sgio;
			push @type_rules, $grammar_rule;
		}
	}
	print "\n\n$query_type:\n".join("|\n\t", @type_rules).";\n\n";
}

print STDERR Dumper \%errors;
exit;


#!/usr/bin/perl

use strict;
use lib 'lib';
use lib '../lib';

use English '-no_match_vars';
use Getopt::Long;

use GenTest;
use GenTest::QueryPerformance;
use GenTest::QueryPerformanceDelta;
use GenTest::Constants;

my ($in_file_name, $filter);

say("Please see http://forge.mysql.com/wiki/Category:RandomQueryGenerator for more information on this test framework.");
say("Starting $0 ".join(" ", @ARGV));

my $opt_result = GetOptions(
	'input-file=s'	=> \$in_file_name,
	'filter=s'	=> \$filter
);

if ($opt_result == 0) {
	exit(STATUS_ENVIRONMENT_FAILURE);
} elsif (not defined $in_file_name) {
        say("The following option is required: --input-file");
        exit(STATUS_ENVIRONMENT_FAILURE);
}

say("Filter: $filter") if defined $filter;

my %counters = (
	incoming_queries	=> 0,
	reported_queries	=> 0
);

open (IN_FILE, "<$in_file_name") or die "Unable to open input file $in_file_name: $!";
$INPUT_RECORD_SEPARATOR = " ]]>\n";

while (<IN_FILE>) {
	$_ =~ s{^<!\[CDATA\[ }{}sgio;
	chomp($_);

	my $VAR1;
	my $performance_delta = eval($_);
	die("Error reading $in_file_name: $@") if $@ ne '';

	$counters{incoming_queries}++;

	if ($performance_delta->matchesFilter($filter) == STATUS_OK) {
		$counters{reported_queries}++;
		print $performance_delta->toString();
	}
}

say("Run statistics:");
say("Incoming: $counters{incoming_queries} queries.");
say("Reported: $counters{reported_queries} queries.");

close IN_FILE;


#!/usr/bin/perl

use strict;
use lib 'lib';
use lib '../lib';

use Data::Dumper;
use Getopt::Long;

use GenTest;
use GenTest::Generator::FromDirectory;
use GenTest::QueryPerformance;
use GenTest::QueryPerformanceDelta;
use GenTest::Executor;
use GenTest::Executor::MySQL;
use GenTest::Constants;
use GenTest::Comparator;

$| = 1;

my (@dsns, $filter, $in_dir_name, $out_file_name);

say("Please see http://forge.mysql.com/wiki/Category:RandomQueryGenerator for more information on this test framework.");
say("Starting $0 ".join(" ", @ARGV));

my $opt_result = GetOptions(
	'dsn1=s'		=> \$dsns[0],
        'dsn2=s'		=> \$dsns[1],
	'input-directory=s'	=> \$in_dir_name,
	'output-file=s'		=> \$out_file_name,
	'filter=s'		=> \$filter
);

if ($opt_result == 0) {
	exit(STATUS_ENVIRONMENT_FAILURE);
} elsif (not (defined $dsns[0] && defined $dsns[1] && defined $in_dir_name)) {
	say("The following options are required: --dsn1 , --dsn2 , --input-directory");
	exit(STATUS_ENVIRONMENT_FAILURE);
}

if (defined $out_file_name) {
	open (OUT_FILE, ">$out_file_name") or die "Unable to open output file $out_file_name: $!";
	say("Dumping results to $out_file_name.");
	select OUT_FILE; $| = 1; select STDOUT;
}

if (not defined $filter) {
	say("No filter defined. All results will be dumped.");
} else {
	say("Filter: $filter") if defined $filter;
}

my @executors;

foreach my $server_id (0..1) {
	say("Connecting to server at DSN $dsns[$server_id] ...");
	my $executor = GenTest::Executor->newFromDSN($dsns[$server_id]);

	exit(STATUS_ENVIRONMENT_FAILURE) if $executor->init() != STATUS_OK;

#	if (!$executor->read_only()) {
#		say("Executor for dsn: ".$executor->dsn()." has been granted more than just SELECT privilege. Please restrict the user and try again");
#		exit(STATUS_ENVIRONMENT_FAILURE);
#	} else {
		$executor->setFlags($executor->flags() | EXECUTOR_FLAG_PERFORMANCE | EXECUTOR_FLAG_HASH_DATA );
#	}

#	$executor->execute("SET GLOBAL innodb_stats_sample_pages = 128");
#	$executor->execute("SHOW TABLE STATUS");

	$executors[$server_id] = $executor;
	say("... done.");
}

my $generator = GenTest::Generator::FromDirectory->new( directory_name => $in_dir_name );
my %counters = (
	incoming_queries	=> 0,
	executed_queries	=> 0,
	reported_queries	=> 0,
	error_queries		=> 0,
	diverging_queries	=> 0
);

query: while (my $query_ref = $generator->next(\@executors)) {
	$counters{incoming_queries}++;
	last if $query_ref == STATUS_EOF;
	my $query = $query_ref->[0];
	next if $query !~ m{\s*SELECT}sgio;
	$counters{executed_queries}++;

	foreach my $temperature ('cold','warm') {
		my @results;
		foreach my $server_id (0..1) {
			$results[$server_id] = $executors[$server_id]->execute($query);
		}

		if (($results[0]->status() != STATUS_OK) || ($results[1]->status() != STATUS_OK)) {
			$counters{error_queries}++;
			next query;
		} elsif (GenTest::Comparator::compare($results[0], $results[1]) != STATUS_OK) {
	                say("The two servers returned different result sets for query: $query ;");
			$counters{diverging_queries}++;
			next query;
		}

		my $performance_delta = GenTest::QueryPerformanceDelta->new(
			query => $query,
			temperature => $temperature,
			performances => [ $results[0]->performance() , $results[1]->performance() ]
		);

		if ($performance_delta->matchesFilter($filter) == STATUS_OK) {
			$counters{reported_queries}++;
			print $performance_delta->toString();
			print OUT_FILE $performance_delta->serialize() if defined $out_file_name;
		}
	}
}

say("Run statistics:");
say("Incoming: $counters{incoming_queries} queries.");
say("Executed: $counters{executed_queries} queries.");
say("Reported: $counters{reported_queries} queries.");
say();
say("Errors: $counters{error_queries} queries.");
say("Diverging results: $counters{diverging_queries} queries.");

close OUT_FILE if defined $out_file_name;


#!/usr/bin/perl

# Copyright (C) 2009 Sun Microsystems, Inc. All rights reserved.  Use
# is subject to license terms.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA

use lib unit;

use strict;

use Test::Unit::Debug qw(debug_pkgs);
use Test::Unit::TestRunner;
use RQGRunner;

use Time::HiRes;

# Uncomment and edit to debug individual packages.
# debug_pkgs(qw/Test::Unit::TestCase/);

my $start_time = Time::HiRes::time();

my $testrunner = RQGRunner->new();
my $result = $testrunner->start(@ARGV);

my $stop_time = Time::HiRes::time();

open TM,">unit/totaltime.dat";
print TM "YVALUE = ".($stop_time - $start_time)."\n";
close TM;

exit $result;


# Copyright (C) 2008-2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
# USA

## Hunting for bugs.
##
## Repeated runs of runall with variation of seed and mask values.
##
## There will be a message in case some conditions are fulfilled.
## ==============================================================
## Message about           | Fulfilled conditions
##                         |
## --------------------------------------------------------------------------------------------------
## runall status code      | desired_status_codes is defined and we just reached one of them
## --------------------------------------------------------------------------------------------------
## matching output pattern | (expected_outputs is defined and one of the patterns matched)
##                         | and (desired_status_codes is not defined
##                         |      or desired_status_codes is defined and we just reached one of them)
##
##
## The protocol of some RQG run will be not deleted in case of
## ===========================================================
## runall status code <> 0
## or
## desired_status_codes is not defined, expected_outputs is defined and we just reached one of them
##
## If "--stop_on_match" is set a bughunt terminates in case of
## ===========================================================
## if desired_status_codes is defined and we just reached one of them
## and
## if expected_outputs is defined we found all patterns.
##
## The various options are explained in bughunt_template.cfg.
##

use strict;
use lib 'lib';
use lib '../lib';
use DBI;
use Carp;
use Getopt::Long;
use Data::Dumper;
use File::Copy;

use GenTest;
use GenTest::Constants;
use GenTest::Grammar;
use GenTest::Properties;
use GenTest::Simplifier::Grammar;
use Time::HiRes;

my $options = {};
GetOptions($options,
           'config=s',
           'grammar=s',
           'redefine=s',
           'trials=i',
           'initial_seed=i',
           'storage_prefix=s',
           'expected_outputs=s@',
           'desired_status_codes=s@',
           'rqg_options=s%',
           'basedir=s',
           'vardir_prefix=s',
           'mysqld=s%',
           'stop_on_match!');
my $config = GenTest::Properties->new(
    options => $options,
    legal => ['desired_status_codes',
              'expected_outputs',
              'grammar',
              'gendata',
              'redefine',
              'trials',
              'initial_seed',
              'mask_level',
              'initial_mask',
              'search_var_size',
              'rqg_options',
              'basedir',
              'vardir_prefix',
              'storage_prefix',
              'stop_on_match',
              'mysqld'],
    required=>['rqg_options',
               'grammar',
               'basedir',
               'vardir_prefix',
               'storage_prefix'],
    defaults => {search_var_size=>10000,
                 trials=>1}
    );

# Dump settings
$config->printProps;

## Calculate mysqld and rqg options

my $mysqlopt = $config->genOpt("--mysqld=--",$config->mysqld)
    if defined $config->mysqld;

my $rqgoptions = $config->genOpt('--', 'rqg_options');

# Determine some runtime parameter, check parameters, ....

my $run_id = time();

say("The ID of this run is $run_id.");

if ( ! -d $config->vardir_prefix ) {
    croak("vardir_prefix '"
          . $config->vardir_prefix .
          "' is not an existing directory");
}

my $vardir = $config->vardir_prefix . '/var_' . $run_id;
mkdir ($vardir);
push my @mtr_options, "--vardir=$vardir";

if ( ! -d $config->storage_prefix) {
    croak("storage_prefix '"
          . $config->storage_prefix .
          "' is not an existing directory");
}
my $storage = $config->storage_prefix.'/'.$run_id;
say "Storage is $storage";
mkdir ($storage);

# We must work on a copy of our test grammars because the original grammars could
# be modified during the bughunt or before inspection of the bughunt results.
my $sql_grammar = $storage."/bughunt_sql.yy";
copy($config->grammar, $sql_grammar)
    or croak("File " . $config->grammar . " cannot be copied to " . $sql_grammar );
my $data_grammar = "";
if ( defined $config->gendata ) {
   $data_grammar = $storage."/bughunt_data.zz";
   copy($config->gendata, $data_grammar)
       or croak("File " . $config->gendata . " cannot be copied to " . $data_grammar );
   $rqgoptions = $rqgoptions . " --gendata=" . $data_grammar;
}
my $redefine_grammar = "";
if ( defined $config->redefine ) {
   $redefine_grammar = $storage."/bughunt_sql_redefine.yy";
   copy($config->redefine, $redefine_grammar)
       or croak("File " . $config->redefine . " cannot be copied to " . $redefine_grammar );
   $rqgoptions = $rqgoptions . " --redefine=" . $redefine_grammar;
}

# Some bugs can be investigating using the core file and the server binary.
# Make a copy of the server binary.
# Attention: In the moment we do not use the copy during testing like the grammars.
# FIXME: There is at least one more location where the "mysqld" binary might be stored.
copy($config->basedir.'/sql/mysqld', $storage.'/mysqld');
$rqgoptions = $rqgoptions . " --basedir=" . $config->basedir;

my $good_seed = $config->initial_seed;
my $mask_level = $config->mask_level;
my $good_mask = $config->initial_mask;
my $current_seed;
my $current_mask;
my $current_rqg_log;
my $errfile = $vardir . '/log/master.err';
my $preserve_log;
foreach my $trial (1..$config->trials) {
    say("###### run_id = $run_id; trial = $trial ######");

    $current_seed = $good_seed - 1 + $trial;
    $current_mask = $good_mask - 1 + $trial;
    $current_rqg_log = $storage . '/' . $trial . '.log';
    $preserve_log = 0;

    my $start_time = Time::HiRes::time();

    my $runall =
        "perl runall.pl ".
        " $rqgoptions $mysqlopt ".
        "--grammar=".$sql_grammar." ".
        "--vardir=$vardir ".
        "--mask-level=$mask_level ".
        "--mask=$current_mask ".
        "--seed=$current_seed >$current_rqg_log 2>&1";

    say($runall);
    my $runall_status = system($runall);
    $runall_status = $runall_status >> 8;

    if ($runall_status == STATUS_UNKNOWN_ERROR) {
       say("runall_status = $runall_status");
       say("Maybe the server startup options are wrong.");
       say("Abort");
       exit STATUS_UNKNOWN_ERROR;
    }

    my $end_time = Time::HiRes::time();
    my $duration = $end_time - $start_time;

    say("runall_status = $runall_status; duration = $duration");

    if ($runall_status != 0) {$preserve_log = 1};
    if (defined $config->desired_status_codes) {
        foreach my $desired_status_code (@{$config->desired_status_codes}) {
            if (($runall_status == $desired_status_code) ||
                (($runall_status != 0) &&
                 ($desired_status_code == STATUS_ANY_ERROR))) {
                say ("###### Found status $runall_status ######");
                if (defined $config->expected_outputs) {
                    checkLogForPattern();
                } else {
                    exit STATUS_OK if $config->stop_on_match;
                }
            }
        }
    } elsif (defined $config->expected_outputs) {
        checkLogForPattern();
    }
    # Save storage space by deleting the log of a non important run.
    if ($preserve_log == 0) {
       unlink($current_rqg_log)
    } else {
      # Backup vardir, the grammars and the mysqld binary
      # Attention: There might be warnings about missing grammar files
      # Sleep a bit with the intention to avoid that the archiver comes up with a
      # warning like "<vardir>/master-data/ib_logfile1: File changed during reading
      sleep 10;
      my $save_cmd = 'tar czf ' . $storage . '/' . $trial . '.tgz ' . $vardir . ' ' . $current_rqg_log . ' ' . $sql_grammar . ' ' . $data_grammar . ' ' . $redefine_grammar . ' ' . $storage.'/mysqld' ;
      say("save_cmd: ->$save_cmd<-");
      my $save_vardir = system($save_cmd);
      # FIXME: Abort in case the call to tar fails
    }

}

#############################

sub checkLogForPattern {
    open (my $my_logfile,'<'.$current_rqg_log)
        or croak "unable to open $current_rqg_log : $!";

    my @filestats = stat($current_rqg_log);
    my $filesize = $filestats[7];
    my $offset = $filesize - $config->search_var_size;

    ## Ensure the offset is not negative
    $offset = 0 if $offset < 0;
    read($my_logfile, my $rqgtest_output,
         $config->search_var_size,
         $offset );
    close ($my_logfile);

    my $match_on_all=1;
    foreach my $expected_output (@{$config->expected_outputs}) {
        if ($rqgtest_output =~ m{$expected_output}sio) {
            say ("###### Found pattern: $expected_output ######");
            $preserve_log = 1;
        } else {
            say ("###### Not found pattern: $expected_output ######");
            $match_on_all = 0;
        }
    }
    exit STATUS_OK if $config->stop_on_match and $match_on_all;
}