#!/usr/bin/perl -w
#---------------------------------------------------------------------
#/* Copyright (C) 2000-2006 MySQL AB
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.

#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.

#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# Version 1.1
#------------------------------------------------------------------------
# Purpose: This application test the performance of creating, dropping 
#          and loading simple and complex tables. 
#------------------------------------------------------------------------
#
#-----------------------------------------------
#             Perl Includes 
#-----------------------------------------------
use DBI;
use Getopt::Long;
use Time::Local;
use Time::localtime;
use IO::File;
#-----------------------------------------------
#   Globals Vars  
#-----------------------------------------------
our $loop_count = 6;
our $t1_count = 10000;
our $t2_count = 10000;
our $our_host='localhost'; 
our $our_port='3306';
our $our_user='root';
our $our_pass='';
our $our_database='perf';
our $dbhM='';
our $our_engine_type='NDB';
our $our_lfg_name='lg1';
our $our_ts_name='ts1'; 
our $our_diskData=0;
our $our_mixData=0;
our $our_num_undo=1;
our $our_skipLFG=0;
our $our_num_data=2;
our $our_cfiles=0;
our $our_sockPath='/tmp/mysql.sock';
our $our_useSock=0;
our $sth_t1_drop='';
our $sth_t2_drop='';
our $sth_t1_create='';
our $sth_t1_create_dd='';
our $sth_t2_create='';
our $sth_t2_create_dd='';
our $blob_data='';
our $blob_file='./ndb_cpcd';
#-------------------------------------------------
#   Sub Pototypes 
#-------------------------------------------------

sub main ();
sub CollectCommandPromptInfo ();
sub ConnectToDatabases ();
sub DisconnectFromDatabase ();
sub CreateDB ();
sub Create_Tables ();
sub Load_t1 (); 
sub Load_t2 ();
sub ShowVars ();
sub Usage ();
sub Prep_Statements ();
sub Simple_Table_Ops ();
sub Simple_Table_Load_Ops ();
sub Complex_Table_Ops ();
sub Complex_Table_Load_Ops ();

#--------------------------------------------------
#  Program Main 
#--------------------------------------------------

main();

sub main ()
{
  CollectCommandPromptInfo();
  ConnectToDatabases();
  CreateDB();
  Prep_Statements();
  #Simple_Table_Ops();
  #Simple_Table_Load_Ops();
  #Complex_Table_Ops();
  Complex_Table_Load_Ops();
  DisconnectFromDatabase;
}

#--------------------------------
# Usage
#--------------------------------
sub Usage ()
{
 ShowVars();
 die "\n\nProgram: Load perf tables;
       usage: load_tpcb.pl
         -he [--help]            :print usage

         -ho [--host=string]     :host name     (default localhost)

         -u  [--user=string]     :user's name   (default root)

         -po [--port=int]        :port          (default 3306)

         -sock [--socket]        :Connect using socket (default false)

         -sp [--spath=string]    :socket path and file name 
                                  (default /tmp/mysql.sock)

         -pa [--pass=string]     :password | Note: leave -pa empty or do not
                                             include for blank password
                                             (default null/BLANK)
         
         -e  [--engine=string]   :engine_type | See Below  
 
         -d  [--database=string] :database name (default perf)

         -lf  [--lfgname}         :Log File Group Name. (default lg1)

         -numL [--numLFGUndo]    :Number of LFG Undo Files. (default 1)

         -sk  [--skipLFGcreate]   :Skip creating the LFG. Use if the LFG
                                  already exists. (default false)
         
         -t  [--tsName]          :Table Space Name.(default ts1)

         -numT [--numTSData]     :Number of Table Space Data Files. (default 2).

         Notes: engine == ndb, ndbdd(Disk Data), ndbmix(mix of mem and DD),\n
                          ndbcluster, InnoDB, MyISAM\n";
}

#--------------------------------
# Show command line values 
#--------------------------------

sub ShowVars ()
{
 ########## Show the user command line values for debugging #########
  print "*********************************************\n";
  print "************ Command-line values ************\n";
  print "*********************************************\n";
  print "Host ..................... $our_host\n";
  print "User ..................... $our_user\n";
  print "Password ................. $our_pass\n" if ($our_pass ne '');
  print "Password ................. BLANK\n" if ($our_pass eq '');
  print "Port ..................... $our_port\n";
  print "Use Socket To Connect .... TRUE\n" if ($our_useSock);
  print "Use Socket To Connect .... FALSE\n" if (!$our_useSock);
  print "Socket Path .............. $our_sockPath\n" if ($our_useSock);
  print "Database ................. $our_database\n";
  print "Engine Type .............. $our_engine_type\n";
  print "Use Disk Data ............ TRUE\n" if ($diskData || $mixData);
  print "Use Disk Data ............ FALSE\n" if (!$diskData && !$mixData);
  print "LFG Name ................. $our_lfg_name\n" if ($diskData || 
                                                         $mixData);
  print "Create Log File Group .... TRUE\n" if ($diskData ||
                                                $mixData &&
                                                !$our_skipLFG);
  print "Create Log File Group .... FALSE\n" if ($diskData ||
                                                $mixData &&
                                                $our_skipLFG);
  print "Number LFG Undo File(s)... $our_num_undo\n" if ($diskData ||
                                                         $mixData);
  print "Table Space Name ......... $our_ts_name\n" if ($diskData ||
                                                         $mixData);
  print "Number TS Data Files(s)... $our_num_data\n" if ($diskData ||
                                                         $mixData);
}

#--------------------------------
#  Collect Command Prompt Info 
#--------------------------------
sub CollectCommandPromptInfo ()
{

  if (!GetOptions("help"=>\$help,
                  "host:s"=>\$our_host,
                  "user:s"=>\$our_user,
                  "port:i"=>\$our_port,
                  "socket"=>\$our_useSock,
                  "spath:s"=>\$our_sockPath,
                  "pass:s"=>\$our_pass,
                  "engine:s"=>\$our_engine_type,
                  "database:s"=>\$our_database,
                  "lfgname:s"=>\$our_lfg_name,
                  "numLFGUndo:i"=>\$our_num_undo,
                  "skipLFGcreate"=>\$our_skipLFG,
                  "tsName:s"=>\$our_ts_name,
                  "numTSData:i"=>\$our_num_data))
  {
    Usage();
  }

  if ($help){Usage();}


  if ($our_useSock){
    $ENV{MYSQL_UNIX_PORT} = $our_sockPath;
  }

  if ($our_engine_type ne 'ndb' && $our_engine_type ne 'ndbcluster'
      && $our_engine_type ne 'InnoDB' && $our_engine_type ne 'MyISAM' 
      && $our_engine_type ne 'innodb' && $our_engine_type ne 'myisam' 
      && $our_engine_type ne 'NDBDD' && $our_engine_type ne 'NDBMIX' 
      && $our_engine_type ne 'ndbdd' && $our_engine_type ne 'ndbmix'
      && $our_engine_type ne 'NDB' && $our_engine_type ne 'NDBCLUSTER'){
    die Usage();
  } 
  if ($our_engine_type eq 'ndbdd'){$our_engine_type = "ndb"; $diskData = 1;}
  if ($our_engine_type eq 'ndbmix'){$our_engine_type = "ndb"; $mixData = 1;}
  if ($our_engine_type eq 'NDBDD'){$our_engine_type = "ndb"; $diskData = 1;}
  if ($our_engine_type eq 'NDBMIX'){$our_engine_type = "ndb"; $mixData = 1;}

  ShowVars();
}

#---------------------------------------------
#  Connect to database & Read from file
#---------------------------------------------
sub ConnectToDatabases ()
{
  if (!$our_useSock){
    $dbhM = DBI->connect("dbi:mysql:database=mysql;host=$our_host;port=$our_port", 
                       "$our_user", "$our_pass")
     or die "Can't connect to MySQL process! Error: $DBI::errstr\n";
  }
  else{
    $dbhM = DBI->connect("DBI:mysql:database=mysql;host=$our_host", 
                        "$our_user", "$our_pass", {'RaiseError' => 1})
      or die "Can't connect to MySQL process! Error: $DBI::errstr\n";
  } 
  print " Connected to MySQLD.\n";
  open(my $fh, $blob_file ) or die $!;
  read( $fh, $blob_data, -s $fh );
  close($fh);
}

#-----------------------------------------------
#  Disconnect from database 
#-----------------------------------------------
sub DisconnectFromDatabase ()
{
  $sth_t1_drop->finish();
  $sth_t2_drop->finish();
  $sth_t1_create->finish();
  $sth_t1_create_dd->finish();
  $sth_t2_create->finish();
  $sth_t1_create_dd->finish();
  $dbhM->disconnect
    or warn " Disconnection failed: $DBI::errstr\n";
  print "Disconnected from MySQLD.\n";
}

#-------------------------------------------------
#  Create database 
#-------------------------------------------------
sub CreateDB ()
{
  print "Creating database!\n";

  $sth = $dbhM->prepare("DROP DATABASE IF EXISTS $our_database;")
	or die "Prepare error: ", $dbhM->errstr;
  $sth->execute();#/Don't care if returns success. No "die" needed
  $sth->finish();

  $sth = $dbhM->prepare("CREATE DATABASE $our_database;")
    or die "Prepare error: ", $dbhM->errstr;
  $sth->execute()
    or die "Create DB Error: ", $sth->errstr;
  $sth->finish();

  $sth = $dbhM->prepare("USE $our_database;")
    or die "Prepare error: ", $dbhM->errstr;
  $sth->execute()
    or die "USE DB Error: ", $sth->errstr;
  $sth->finish();

  print "here 1\n";
  if($diskData || $mixData && !$our_skipLFG){
    print "Creating LFG $our_lfg_name....\n";
    $sth = $dbhM->prepare("CREATE LOGFILE GROUP $our_lfg_name
                           ADD UNDOFILE './$our_lfg_name/undofile.dat'
                           INITIAL_SIZE 250M
                           UNDO_BUFFER_SIZE = 4M
                           ENGINE=NDB;")
      or die "Prepare CREATE LOGFILE GROUP error: ", $dbhM->errstr;
    $sth->execute()
      or die "CREATE LOGFILE GROUP error: ", $sth->errstr;
    $sth->finish();
   
  print "here 2\n";
    if($our_num_undo > 1){
      $undo_count = $our_num_undo - 1;
      print "Adding additional undo files, please stand by....\n";
      while ( $undo_count > 0){
        $file="undofile".$undo_count.".dat";
        print "Adding $file..\n";
        $sth = $dbhM->prepare("ALTER LOGFILE GROUP $our_lfg_name
                               ADD UNDOFILE './$our_lfg_name/$file'
                               INITIAL_SIZE 250M
                               ENGINE=NDB;")
          or die "Prepare ALTER LOGFILE GROUP error: ", $dbhM->errstr;
        $sth->execute()
          or die "ALTER LOGFILE GROUP error: ", $sth->errstr;
        $sth->finish();
        $undo_count--;
      }
    }
  }
  print "here 3\n";
   
  if($diskData || $mixData){
    print "Creating TS $our_ts_name....\n";
    $sth = $dbhM->prepare("CREATE TABLESPACE $our_ts_name
                           ADD DATAFILE './$our_ts_name/datafile.dat'
                           USE LOGFILE GROUP $our_lfg_name
                           INITIAL_SIZE 500M
                           ENGINE=NDB;")
      or die "Prepare CREATE TABLESPACE error: ", $dbhM->errstr;
    $sth->execute()
      or die "CREATE TABLESPACE error: ", $sth->errstr;
    $sth->finish();
  
    if($our_num_data > 1){
      $data_count = $our_num_data - 1;
      while  ($data_count > 0){
        $file="datafile".$data_count.".dat";
        print "Add data file $file\n";
        $sth = $dbhM->prepare("ALTER TABLESPACE $our_ts_name
                               ADD DATAFILE './$our_ts_name/$file'
                               INITIAL_SIZE 500M
                               ENGINE=NDB;")
          or die "Prepare ALTER TABLE SPACE error: ", $dbhM->errstr;
        $sth->execute()
          or die "ALTER TABLE SPACE error: ", $sth->errstr;
        $sth->finish();
        $data_count--;
      }
    }
  }
  print "Database Created.\n";
}

#------------------------------------------------------
#  Prepare Statements 
#------------------------------------------------------
sub Prep_Statements ()
{

  $sth_t1_drop = $dbhM->prepare("DROP TABLE IF EXISTS t1;")
	or die "Prepare drop account error: ", $dbhM->errstr;

  $sth_t2_drop = $dbhM->prepare("DROP TABLE IF EXISTS t2;")
	or die "Prepare drop branch error: ", $dbhM->errstr;


  $sth_t1_create = $dbhM->prepare("CREATE TABLE t1 (c1 INT PRIMARY KEY)
                                   ENGINE=$our_engine_type;")
      or die "Prepare Create t1 Error: ", $dbhM->errstr;
    
  $sth_t2_create = $dbhM->prepare("CREATE TABLE t2 
                                   (c1 int Primary Key, 
                                    c2 decimal(8,2),
                                    c3 bit, c4 text, c5 BLOB,
                                    c6 TEXT, c7 double, c8 float)
                                    ENGINE=$our_engine_type;")
      or die "Prepare Create t2 Error: ", $dbhM->errstr;

  $sth_t1_create_dd = $dbhM->prepare("CREATE TABLE t1 (c1 INT PRIMARY KEY)
                                   STORAGE DISK ENGINE=$our_engine_type;")
      or die "Prepare Create t1 DD Error: ", $dbhM->errstr;
   
  $sth_t2_create_dd = $dbhM->prepare("CREATE TABLE t2 (c1 int Primary Key, 
                                      c2 decimal(8,2), c3 CHAR, c4 text, c5 BLOB,
                                      c6 VARCHAR(20), c7 double, c8 float)
                                      TABLESPACE $our_ts_name
                                      STORAGE DISK ENGINE=$our_engine_type;")
      or die "Prepare Create t2 DD Error: ", $dbhM->errstr;
}

#-----------------------------------------------
#  Load t1 
#-----------------------------------------------
sub Load_t1 ()
{
  print "Loading t1 table -- Please wait\n";
  $sth = $dbhM->prepare("INSERT into t1 VALUES(?);")
     or die "Prepare insert into t1 error: ", $dbhM->errstr;
  $i = 0;
  $startTime = time;
  while($i < $t1_count){
    $i++;
    $sth->bind_param(1, $i);
    $sth->execute()
      or die "insert into t1 Error: ", $sth->errstr;
  }
  $sth->finish();
  $end_time = time - $startTime;
  print "Time to load took $end_time seconds\n";
  $end_time = 0;
}

#-----------------------------------------------
#  Load t2
#-----------------------------------------------
sub Load_t2 ()
{
  print "Loading t2 table -- Please wait\n";
  $sth = $dbhM->prepare("INSERT into t2 values(?, ?, 
                                               ?, ?,
                                               ?, ?,
                                               ?, ? );")
    or die "Prepare insert into t2 error: ", $dbhM->errstr;
  $i = 0;
  $startTime = time;
  while($i < $t2_count){
    $i++;
    $sth->bind_param(1, $i);
    $sth->bind_param(2, 3.00);
    $sth->bind_param(3, "G");
    $sth->bind_param(4, "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
                         GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
                         _G_G_G_G_G");
    $sth->bind_param(5, $blob_data);
    $sth->bind_param(6, "Good testing");
    $sth->bind_param(7, 88888888);
    $sth->bind_param(8, 32.0009);
    $sth->execute()
      or die "insert into t2 Error: ", $sth->errstr;
  }
  $sth->finish();
  $end_time = time - $startTime;
  print "Time to load t2 = $end_time seconds\n";
  $end_time = 0;
}

#-----------------------------------------------
#  Simple Table Operations
#-----------------------------------------------
sub Simple_Table_Ops ()
{
  $loop = 0;
  while ($loop < $loop_count){
    if (!$diskData){
      $loop++;
      $startTime = time;
      $sth_t1_create->execute();
      $end_time = time - $startTime;
      print "Time to create t1 = $end_time seconds\n";
      $end_time = 0;
      $startTime = time;
      $sth_t1_drop->execute();
      $end_time = time - $startTime;
      print "Time to drop t1 = $end_time seconds\n";
      $end_time = 0;
    }
    else{
      $loop++;
      $startTime = time;
      $sth_t1_create_dd->execute();
      $end_time = time - $startTime;
      print "Time to create t1 DD = $end_time seconds\n";
      $end_time = 0;
      $startTime = time;
      $sth_t1_drop->execute();
      $end_time = time - $startTime;
      print "Time to drop t1 DD = $end_time seconds\n";
      $end_time = 0;
    }
  }
}

#-----------------------------------------------
#  Simple Table Load Operations
#-----------------------------------------------
sub Simple_Table_Load_Ops ()
{
  $loop = 0;
  while ($loop < $loop_count){
    if (!$diskData){
      $loop++;
      $startTime = time;
      $sth_t1_create->execute();
      $end_time = time - $startTime;
      print "Time to create t1 = $end_time seconds\n";
      $end_time = 0;
      Load_t1();
      $startTime = time;
      $sth_t1_drop->execute();
      $end_time = time - $startTime;
      print "Time to drop t1 = $end_time seconds\n";
      $end_time = 0;
    }
    else{
      $loop++;
      $startTime = time;
      $sth_t1_create_dd->execute();
      $end_time = time - $startTime;
      print "Time to create t1 DD = $end_time seconds\n";
      $end_time = 0;
      Load_t1();
      $startTime = time;
      $sth_t1_drop->execute();
      $end_time = time - $startTime;
      print "Time to drop t1 DD = $end_time seconds\n";
      $end_time = 0;
    }
  }
}

#-----------------------------------------------
#  Complex Table Operations
#-----------------------------------------------
sub Complex_Table_Ops ()
{
  $loop = 0;
  while ($loop < $loop_count){
    if (!$diskData){
      $loop++;
      $startTime = time;
      $sth_t2_create->execute();
      $end_time = time - $startTime;
      print "Time to create t2 = $end_time seconds\n";
      $end_time = 0;
      $startTime = time;
      $sth_t2_drop->execute();
      $end_time = time - $startTime;
      print "Time to drop t2 = $end_time seconds\n";
      $end_time = 0;
    }
    else{
      $loop++;
      $startTime = time;
      $sth_t2_create_dd->execute();
      $end_time = time - $startTime;
      print "Time to create t2 DD = $end_time seconds\n";
      $end_time = 0;
      $startTime = time;
      $sth_t2_drop->execute();
      $end_time = time - $startTime;
      print "Time to drop t2 DD = $end_time seconds\n";
      $end_time = 0;
    }
  }
}

#-----------------------------------------------
#  Complex Table Load Operations
#-----------------------------------------------
sub Complex_Table_Load_Ops ()
{
  $loop = 0;
  while ($loop < $loop_count){
    if (!$diskData){
      $loop++;
      $startTime = time;
      $sth_t2_create->execute();
      $end_time = time - $startTime;
      print "Time to create t2 = $end_time seconds\n";
      $end_time = 0;
      Load_t2();
      $startTime = time;
      $sth_t2_drop->execute();
      $end_time = time - $startTime;
      print "Time to drop t2 = $end_time seconds\n";
      $end_time = 0;
    }
    else{
      $loop++;
      $startTime = time;
      $sth_t2_create_dd->execute();
      $end_time = time - $startTime;
      print "Time to create t2 DD = $end_time seconds\n";
      $end_time = 0;
      Load_t2();
      $startTime = time;
      $sth_t2_drop->execute();
      $end_time = time - $startTime;
      print "Time to drop t2 DD = $end_time seconds\n";
      $end_time = 0;
    }
  }
}
###################  End of script #############
