open System.Diagnostics

(* Raima.Rdm is the system module that contains the ADO.NET data provider
   for RDM *)
open Raima.Rdm

(* EXAMPLE - Perf02 for F# using ADO.NET *)
(* This is a simple performance example creates 50,000 rows in a simple table
 * in an on-disk database, using the least transactionally safe method
 * available (TFSS).  It then reads (and sums) the rows.  Finally it deletes
 * the rows.  The times to execute each of these operations is reported.
 * 
 * The following methods are illustrated:
 *     Raima.Rdm.RdmConnection:
 *         ChangeDatabase(string) Method
 *         Close() Method
 *         CreateCommand() Method
 *         Open() Method
 *         RdmConnection(String) Constructor
 *     Raima.Rdm.RdmCommand:
 *         CommandText Property
 *         ExecuteNonQuery() Method
 *         ExecuteScalar() Method
 * 
 * They are fully document in http://docs.raima.com/rdm/.
 * 
 * For simplicity this example does not catch any thrown exceptions
 * but good programming practices would dictate that this occur in
 * a full application.
 *)

let NumRows = 50000

let DropDatabase (conn : RdmConnection) name =
    let cmd = conn.CreateCommand()

    (* Attempt to drop this database.  If the database does not already exist
     * this will fail and we simply ignore the failure for this sample. *)
    try
        cmd.CommandText <- "DROP DATABASE " + name
        cmd.ExecuteNonQuery() |> ignore
    with
        | exn -> ()

let CreateThisDatabase (conn : RdmConnection) name cmds =
    let cmd = conn.CreateCommand()

    cmd.CommandText <- "CREATE DATABASE " + name
    cmd.ExecuteNonQuery() |> ignore

    cmds |>
        Array.iter(fun c ->
            cmd.CommandText <- c
            cmd.ExecuteNonQuery() |> ignore
        )

    cmd.CommandText <- "COMMIT"
    cmd.ExecuteNonQuery() |> ignore

    cmd.CommandText <- "CLOSE " + name
    cmd.ExecuteNonQuery() |> ignore

let CreateDatabases conn =
    (* Drop any existing copies of the databases. *)
    DropDatabase conn "Perf02"

    (* Attempt to create the databases *)
    CreateThisDatabase conn "Perf02" [| "CREATE TABLE Simple (int_col INTEGER)" |]

(* Initialization - Open the connection and create the database *)
let Initialize (conn : RdmConnection) =
    let sw = Stopwatch.StartNew()

    conn.Open()
    CreateDatabases(conn)
    conn.ChangeDatabase("Perf02")
    
    sw.Stop()

    printfn "Initializing with STANDALONE configuration"
    printfn "Preparing a new database:\t\t\t%d millisecs" sw.ElapsedMilliseconds
    printfn "\tOne, simple row type"
    printfn "\tOn disk"
    printfn "\tOpened exclusively"

(* Cleanup - Close the connection *)
let Cleanup (conn : RdmConnection) = 
    let sw = Stopwatch.StartNew()
    conn.Close()
    sw.Stop()

    printfn "Cleanup:\t\t\t\t\t%d millisecs" sw.ElapsedMilliseconds

(* Add 50,000 rows - there is no 'quick' method of inserting rows in
 * bulk in SQL, so we have to execute the INSERT command 50,000 times *)
let AddRows (conn : RdmConnection) =
    let sw = Stopwatch.StartNew()

    let cmd = conn.CreateCommand()
    cmd.CommandText <- "INSERT INTO Simple VALUES 1"

    for ii = 1 to NumRows do
        cmd.ExecuteNonQuery() |> ignore

    sw.Stop()

    printfn "Add %d rows:\t\t\t\t\t%d millisecs" NumRows sw.ElapsedMilliseconds

(* Read all 50,000 rows, summing up the values stored in each one *)
let ReadRows (conn : RdmConnection) =
    let sw = Stopwatch.StartNew()

    let cmd = conn.CreateCommand()
    cmd.CommandText <- "SELECT SUM(int_col) FROM Simple"

    let total = cmd.ExecuteScalar() :?> int

    sw.Stop()

    printfn "Scanning, reading, summing %d rows:\t\t%d millisecs" NumRows sw.ElapsedMilliseconds
    printfn "\tSum = %d" total

(* Update each row, setting its value to one more than it was *)
let UpdateRows (conn : RdmConnection) =
    let sw = Stopwatch.StartNew()

    let cmd = conn.CreateCommand()
    cmd.CommandText <- "UPDATE Simple SET int_col = int_col + 1"
    cmd.ExecuteNonQuery() |> ignore

    sw.Stop()

    printfn "Updating %d rows:\t\t\t\t%d millisecs" NumRows sw.ElapsedMilliseconds

(* Delete all rows *)
let DeleteRows (conn : RdmConnection) =
    let sw = Stopwatch.StartNew()

    let cmd = conn.CreateCommand()
    cmd.CommandText <- "DELETE FROM Simple"
    cmd.ExecuteNonQuery() |> ignore

    sw.Stop()

    printfn "Deleting %d rows:\t\t\t\t%d millisecs" NumRows sw.ElapsedMilliseconds

printfn "Perf02 Example"
printfn ""

(* Create the connection with a simple connection string *)
let conn = new RdmConnection("host=local;openmode=x;tfstype=tfss;autocommit=off")

(* Open the connection, delete any existing database, and create the database
 * anew *)
Initialize conn

(* Add 50,000 rows to a table *)
AddRows conn

(*Read all the rows in the table *)
ReadRows conn

(* Update all the rows in the table *)
UpdateRows conn

(* Read all the rows in the table again *)
ReadRows conn

(* Delete all the rows in the table *)
DeleteRows conn

(* Cleanup *)
Cleanup conn

printfn ""
printfn "Hit <Enter> to continue"
System.Console.ReadLine() |> ignore

