// http://developer.mimer.com/documentation/html_91/Mimer_SQL_Engine_DocSet/Mimer_SQL_Engine.htm
// Loading a driver using the standard Class.forName method is very simple:

import java.io.*;
import java.sql.*;
import java.util.*;

// setenv CLASSPATH ".:mimjdbc2.jar"

class MimerConnection extends Thread {
    private static int nr_threads = 0;
    private int thread_nr = ++nr_threads;
    private String saved_dbname;
    private String url;
    private FlagVector flags;
    Random r = new Random();
    public MimerConnection(String dbname, String user, String password, FlagVector fv) {
	System.out.println("MimerConnection " + thread_nr + ": Created");
	saved_dbname = dbname;
	url = "jdbc:mimer://" + user + ":" + password + "@130.243.104.99/" + dbname;
	flags = fv;
    }

    public void run() {
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Started");
	System.out.println("Threads: " + flags + "\n");
	Connection con;
	try {
	    System.out.println("MimerConnection " + thread_nr + ": Connecting to '" + url + "'");
	    // flags.setFlag(thread_nr, 'W');
	    con = DriverManager.getConnection(url);
	    flags.setFlag(thread_nr, 'C');
	}
	catch (java.sql.SQLException sqe) {
	    flags.setFlag(thread_nr, 'E');
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): *** Connection FAILED");
	    SQLException stk;
	    stk = sqe;   // Save initial exception for stack trace 
	    System.err.println("\n*** SQLException:\n");
	    while (sqe != null) {
		System.err.println("Message:     " + sqe.getMessage());
		System.err.println("SQLState:    " + sqe.getSQLState());
		System.err.println("NativeError: " + sqe.getErrorCode());
		System.err.println();
		sqe = sqe.getNextException();
	    }
	    System.out.println("Threads: " + flags + "\n");
	    return;
	}
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Connected");
	System.out.println("Threads: " + flags + "\n");

	try {
	    flags.setFlag(thread_nr, 'S');
	    sleep(5000);
	    flags.setFlag(thread_nr, 'O');
	}
	catch (InterruptedException e) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + ": *** sleep interrupted! ***");
	}

	/*
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): NOT creating a databank!");
	*/
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Creating the databank...");
	try {
	    Statement stmt = con.createStatement();
	    flags.setFlag(thread_nr, '1');
	    stmt.executeUpdate("CREATE DATABANK dumstore OF 100 PAGES IN 'dumstore.dbf' WITH LOG OPTION");
	    flags.setFlag(thread_nr, 'O');
	    flags.setFlag(thread_nr, '2');
	    stmt.close();
	    flags.setFlag(thread_nr, 'O');
	    // commit the transaction
	    System.out.println();
	    System.out.println("MimerConnection " + thread_nr + ": Commit!");
	    flags.setFlag(thread_nr, '3');
	    con.commit();
	    flags.setFlag(thread_nr, 'O');
	}
	catch (java.sql.SQLException sqe) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): *** Create databank FAILED");
	    SQLException stk;
	    stk = sqe;   // Save initial exception for stack trace 
	    System.err.println("\n*** SQLException:\n");
	    while (sqe != null) {
		System.err.println("Message:     " + sqe.getMessage());
		System.err.println("SQLState:    " + sqe.getSQLState());
		System.err.println("NativeError: " + sqe.getErrorCode());
		System.err.println();
		sqe = sqe.getNextException();
	    }
	    // return;
	    System.out.println("MimerConnection " + thread_nr + ": databank creation failed... continuing anyway...");
	}
	catch (Exception e) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): *** Create databank FAILED with some OTHER exception!");
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): Goodbye from this thread.");
	    flags.setFlag(thread_nr, 'E');
	    System.out.println("Threads: " + flags + "\n");
	    return;
	}
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): databank created");
	System.out.println("Threads: " + flags + "\n");


	/*
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): NOT creating a table!");
	*/
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Creating the table...");
	try {
	    Statement stmt = con.createStatement();
	    flags.setFlag(thread_nr, '4');
	    stmt.executeUpdate("CREATE TABLE Banan(a integer, b integer)");
	    flags.setFlag(thread_nr, 'O');
	    flags.setFlag(thread_nr, '5');
	    stmt.close();
	    flags.setFlag(thread_nr, 'O');
	    // commit the transaction
	    System.out.println();
	    System.out.println("MimerConnection " + thread_nr + ": Commit!");
	    flags.setFlag(thread_nr, '6');
	    con.commit();
	    flags.setFlag(thread_nr, 'O');
	}
	catch (java.sql.SQLException sqe) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): *** Create table FAILED");
	    SQLException stk;
	    stk = sqe;   // Save initial exception for stack trace 
	    System.err.println("\n*** SQLException:\n");
	    while (sqe != null) {
		System.err.println("Message:     " + sqe.getMessage());
		System.err.println("SQLState:    " + sqe.getSQLState());
		System.err.println("NativeError: " + sqe.getErrorCode());
		System.err.println();
		sqe = sqe.getNextException();
	    }
	    // return;
	    System.out.println("MimerConnection " + thread_nr + ": table creation failed... continuing anyway...");
	}
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): table created");
	System.out.println("Threads: " + flags + "\n");


	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Inserting into table...");
	try {
	    Statement stmt = con.createStatement();
	    flags.setFlag(thread_nr, '7');
	    stmt.executeUpdate("insert into Banan(a, b) values(17, 4711)");
	    flags.setFlag(thread_nr, 'O');
	    flags.setFlag(thread_nr, '8');
	    stmt.close();
	    flags.setFlag(thread_nr, 'O');
	    // commit the transaction
	    System.out.println();
	    System.out.println("MimerConnection " + thread_nr + ": Commit!");
	    flags.setFlag(thread_nr, '9');
	    con.commit();
	    flags.setFlag(thread_nr, 'O');
	}
	catch (java.sql.SQLException sqe) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): *** Insert failed");
	    SQLException stk;
	    stk = sqe;   // Save initial exception for stack trace 
	    System.err.println("\n*** SQLException:\n");
	    while (sqe != null) {
		System.err.println("Message:     " + sqe.getMessage());
		System.err.println("SQLState:    " + sqe.getSQLState());
		System.err.println("NativeError: " + sqe.getErrorCode());
		System.err.println();
		sqe = sqe.getNextException();
	    }
	    // return;
	    System.out.println("MimerConnection " + thread_nr + ": insert failed... continuing anyway...");
	}
	catch (Exception q) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): *** Insert FAILED with some OTHER exception!");
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): Goodbye from this thread.");
	    flags.setFlag(thread_nr, 'E');
	    System.out.println("Threads: " + flags + "\n");
	    return;
	}
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): insert done");
	System.out.println("Threads: " + flags + "\n");






	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Simple delete...");
	try {
	    Statement stmt = con.createStatement();
	    flags.setFlag(thread_nr, 'a');
	    stmt.executeUpdate("delete from Banan where a > 50");
	    flags.setFlag(thread_nr, 'O');
	    flags.setFlag(thread_nr, 'b');
	    stmt.close();
	    flags.setFlag(thread_nr, 'O');
	}
	catch (java.sql.SQLException sqe) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): *** Delete failed");
	    SQLException stk;
	    stk = sqe;   // Save initial exception for stack trace 
	    System.err.println("\n*** SQLException:\n");
	    while (sqe != null) {
		System.err.println("Message:     " + sqe.getMessage());
		System.err.println("SQLState:    " + sqe.getSQLState());
		System.err.println("NativeError: " + sqe.getErrorCode());
		System.err.println();
		sqe = sqe.getNextException();
	    }
	    // return;
	    System.out.println("MimerConnection " + thread_nr + ": delete failed... continuing anyway...");
	}
	catch (Exception q) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): *** Delete FAILED with some OTHER exception!");
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): Goodbye from this thread.");
	    flags.setFlag(thread_nr, 'E');
	    System.out.println("Threads: " + flags + "\n");
	    return;
	}
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Simple insert done");
	System.out.println("Threads: " + flags + "\n");



	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Simple insert...");
	try {
	    Statement stmt = con.createStatement();
	    int n1 = Math.abs(r.nextInt()) % 100 + 1;
	    int n2 = Math.abs(r.nextInt()) % 10000 + 1;
	    flags.setFlag(thread_nr, 'c');
	    stmt.executeUpdate("insert into Banan(a, b) values(" + n1 + ", " + n2 + ")");
	    flags.setFlag(thread_nr, 'O');
	    flags.setFlag(thread_nr, 'd');
	    stmt.close();
	    flags.setFlag(thread_nr, 'O');
	}
	catch (java.sql.SQLException sqe) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): *** Insert failed");
	    SQLException stk;
	    stk = sqe;   // Save initial exception for stack trace 
	    System.err.println("\n*** SQLException:\n");
	    while (sqe != null) {
		System.err.println("Message:     " + sqe.getMessage());
		System.err.println("SQLState:    " + sqe.getSQLState());
		System.err.println("NativeError: " + sqe.getErrorCode());
		System.err.println();
		sqe = sqe.getNextException();
	    }
	    // return;
	    System.out.println("MimerConnection " + thread_nr + ": insert failed... continuing anyway...");
	}
	catch (Exception q) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): *** Insert FAILED with some OTHER exception!");
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): Goodbye from this thread.");
	    flags.setFlag(thread_nr, 'E');
	    System.out.println("Threads: " + flags + "\n");
	    return;
	}
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Simple insert done");
	System.out.println("Threads: " + flags + "\n");



	try {
	    flags.setFlag(thread_nr, 'S');
	    sleep(5000);
	    flags.setFlag(thread_nr, 'O');
	}
	catch (InterruptedException e) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + ": *** sleep interrupted! ***");
	}



	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Simple select...");
	try {
	    String query = "select a,b from banan";
	    Statement stmt = con.createStatement();
	    flags.setFlag(thread_nr, 'e');
	    ResultSet rs = stmt.executeQuery(query);
	    flags.setFlag(thread_nr, 'O');
	    int nr_rows = 0;
	    while (rs.next()) {
		String a = rs.getString("a");
		String b = rs.getString("b");
		/*
		System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): A row: " +
				   "A = " + rs.getString("a") + ", " +
				   "B = " + rs.getString("b"));
		*/
		++nr_rows;
	    }
	    System.out.println("MimerConnection " + thread_nr + ": " + nr_rows + " row(s) in result");
	    rs.close();
	    stmt.close();
	}
	catch (java.sql.SQLException sqe) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): *** Select failed");
	    SQLException stk;
	    stk = sqe;   // Save initial exception for stack trace 	    
	    
	    System.err.println("\n*** SQLException:\n");
	    while (sqe != null) {
		System.err.println("Message:     " + sqe.getMessage());
		System.err.println("SQLState:    " + sqe.getSQLState());
		System.err.println("NativeError: " + sqe.getErrorCode());
		System.err.println();
		
		sqe = sqe.getNextException();
	    }	    // int dbnr = Math.abs(r.nextInt()) % NR_DUMBASES + 1;

	}
	catch (Exception q) {
	    flags.setFlag(thread_nr, 'P');
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): *** Select FAILED with some OTHER exception!");
	    System.out.println("MimerConnection " + thread_nr + " (" + url + "): Goodbye from this thread.");
	    flags.setFlag(thread_nr, 'E');
	    System.out.println("Threads: " + flags + "\n");
	    return;
	}
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Simple select finished.");
	System.out.println("Threads: " + flags + "\n");





	flags.setFlag(thread_nr, 'x');
	System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Closing connection...");
	flags.setFlag(thread_nr, 'y');
	try {
	    flags.setFlag(thread_nr, 'z');
	    con.close();
	    flags.setFlag(thread_nr, 'D');
	}
	catch (java.sql.SQLException e) {
	    flags.setFlag(thread_nr, 'E');
	    System.out.println("MimerConnection " + thread_nr + ": *** Close failed. ***");
	}

        System.out.println("MimerConnection " + thread_nr + " (to " + saved_dbname + "): Finished");
	System.out.println("Threads: " + flags + "\n");
    } // run
} // class MimerConnection

// Flags are numbered from 1 to (and including) nrFlags
//
// Flags:
// U = Unconnected
// C = Connected
// D = Done, more or less ok
// E = Done, with errors
// P = Problem, something just went wrong
// W = Waiting for response
// [1-9a-z] = W, at various places in the program
// O = Ok, got a response
// S = Sleeping

class FlagVector {
    private final int nrFlags;
    private final char flags[];
    public FlagVector(int n, char f) {
	nrFlags = n;
	flags = new char[nrFlags + 1];
	for (int i = 0; i <= n; ++i)
	    flags[i] = f;
    }
    synchronized public void setFlag(int n, char f) { flags[n] = f; }
    synchronized public String toString() {
	StringBuffer sb = new StringBuffer(nrFlags);
	for (int i = 1; i <= nrFlags; ++i)
	    sb.append(flags[i]);
	return sb.toString();
    }
} // class FlagVector

class MimerStressTest {
    // public static final int NR_DUMBASES = 72; // Numbered from 1 to NR_DUMBASES
    public static final int NR_DUMBASES = 72;
    // public static final int NR_CONNECTIONS = 100; // Our license max!
    public static final int NR_CONNECTIONS = 72;

    public static void main(String[] args) {
	Vector threads = new Vector();
	System.out.println("************************************************************");
	System.out.println("MimerStressTest: Starting main");
        Random r = new Random();
	FlagVector fv = new FlagVector(NR_CONNECTIONS, 'U');

	System.out.println("MimerStressTest: main: Trying to load driver...");
	try {
	    Class.forName("com.mimer.jdbc.Driver");
	} catch (java.lang.ClassNotFoundException cnf) {
	    System.err.println("*** JDBC driver not found");
	    return;
	}

	/*
	for (int i = 1; i <= NR_CONNECTIONS; ++i) {
	    // int dbnr = Math.abs(r.nextInt()) % NR_DUMBASES + 1;
	    // int dbnr = 10 + i / 10;
	    // int dbnr = i;
	    int dbnr = Math.abs(r.nextInt()) % NR_DUMBASES + 1;
	    // MimerConnection t = new MimerConnection("dumbas" + dbnr, "sysadm", "dumbas" + dbnr);
	    // MimerConnection t = new MimerConnection("dumbas30", "sysadm", "dumbas30");
	    // MimerConnection t = new MimerConnection("example_remotedb", "root", "foo");
	    MimerConnection t = new MimerConnection("dumbas" + dbnr, "sysadm", "dumbas" + dbnr, fv);
	    t.start();
	}
	*/

	for (int i = 1; i <= NR_CONNECTIONS; ++i) {
	    // int dbnr = Math.abs(r.nextInt()) % NR_DUMBASES + 1;
	    // int dbnr = 10 + i / 10;
	    // int dbnr = i;
	    int dbnr = i;
	    // MimerConnection t = new MimerConnection("dumbas" + dbnr, "sysadm", "dumbas" + dbnr);
	    // MimerConnection t = new MimerConnection("dumbas30", "sysadm", "dumbas30");
	    // MimerConnection t = new MimerConnection("example_remotedb", "root", "foo");
	    MimerConnection t = new MimerConnection("dumbas" + dbnr, "sysadm", "dumbas" + dbnr, fv);
	    t.start();
	}
	System.out.println("MimerStressTest: Ending main");
    } // main
} // class MimerStressTest

