using System;
using System.Diagnostics;

/* Raima.Rdm is the system module that contains the ADO.NET
 * data provider for RDM */
using Raima.Rdm;

/* EXAMPLE - Perf06 for C# using ADO.NET */
/* This is a simple performance example creates 50,000 rows in a simple table
 * in an on-disk database, using different transaction sizes (i.e. different
 * number of rows inserted as part of each transaction) to demonstrate the
 * performance difference when using small vs. large transactions.
 * 
 * The following methods are illustrated:
 *     Raima.Rdm.RdmConnection:
 *         ChangeDatabase Method
 *         Close() Method
 *         CreateCommand() Method
 *         Open() Method
 *         RdmConnection() Constructor
 *     Raima.Rdm.RdmCommand:
 *         CommandText Property
 *         ExecuteNonQuery() Method
 * 
 * They are fully document in http://docs.raima.com/rdm/.
 * 
 * For simplicity this example does not catch any thrown execptions
 * but good programming practices would dictate that this occur in
 * a full application.
 */

namespace Perf06_CS_ADO
{
    class Program
    {
        const int NumRows = 50000;

        static void DropDatabase(
            RdmConnection conn,
            string name)
        {
            RdmCommand 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();

                cmd.CommandText = "COMMIT";
                cmd.ExecuteNonQuery();
            }
            catch (Exception)
            {
            }
        }

        static void CreateThisDatabase(
            RdmConnection conn,
            string name,
            string[] cmds)
        {
            RdmCommand cmd = conn.CreateCommand();

            /* Create the specified database.  Make sure the database is
             * closed when we are done so other databases can be created
             * after this if necessary. */
            cmd.CommandText = "CREATE DATABASE " + name;
            cmd.ExecuteNonQuery();

            foreach (string c in cmds)
            {
                cmd.CommandText = c;
                cmd.ExecuteNonQuery();
            }

            cmd.CommandText = "COMMIT";
            cmd.ExecuteNonQuery();

            cmd.CommandText = "CLOSE " + name;
            cmd.ExecuteNonQuery();
        }

        static void CreateDatabases(
            RdmConnection conn)
        {
            string[] cmds =
            {
                "CREATE TABLE Simple (int_col INTEGER)"
            };

            /* Drop any existing copy of the database */
            DropDatabase(conn, "Perf06");

            /* Attempt to create the database */
            CreateThisDatabase(conn, "Perf06", cmds);
        }

        /* Initialization - Open the connection and create the database */
        static void Initialize(RdmConnection conn)
        {
            Stopwatch sw = Stopwatch.StartNew();
            conn.Open();
            CreateDatabases(conn);
            conn.ChangeDatabase("Perf06");
            sw.Stop();

            Console.WriteLine("Initializing with DIRECT-LINK configuration");
            Console.WriteLine("Preparing a new database:\t\t\t" + sw.ElapsedMilliseconds + " millisecs");
            Console.WriteLine("\tOne, simple row type");
            Console.WriteLine("\tOn disk");
            Console.WriteLine("\tOpened exclusively");
        }

        /* Cleanup - Close the connection */
        static void Cleanup(RdmConnection conn)
        {
            Stopwatch sw = Stopwatch.StartNew();
            conn.Close();
            sw.Stop();

            Console.WriteLine("Cleanup:\t\t\t\t\t" + sw.ElapsedMilliseconds + " millisecs");
        }

        /* 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.
         * When adding rows, break them into transactions of 'transactionSize'
         * rows per transaction. */
        static void AddRows(RdmConnection conn, int transactionSize)
        {
            Console.Write("Add {0} rows with {1,-5} rows/transaction:",
                    NumRows, transactionSize);

            Stopwatch sw = Stopwatch.StartNew();

            RdmCommand cmd = conn.CreateCommand();
            cmd.CommandText = "INSERT INTO Simple VALUES 1";

            int            count = 0;
            RdmTransaction trans = null;

            for (int ii = 0; ii < NumRows; ii++)
            {
                if (count == 0)
                    trans = conn.BeginTransaction();

                cmd.ExecuteNonQuery();

                if (++count == transactionSize)
                {
                    trans.Commit();
                    count = 0;
                }
            }

            if (count > 0)
                trans.Commit();

            sw.Stop();

            Console.WriteLine("\t{0} millisecs", sw.ElapsedMilliseconds);
        }

        /* Delete all rows */
        static void DeleteRows(RdmConnection conn)
        {
            Stopwatch sw = Stopwatch.StartNew();

            RdmCommand cmd = conn.CreateCommand();
            cmd.CommandText = "DELETE FROM Simple";

            RdmTransaction trans = conn.BeginTransaction();
            cmd.ExecuteNonQuery();
            trans.Commit();

            sw.Stop();
        }

        static void Main(string[] args)
        {
            int[] transactionSizes = { 50000, 10000, 5000, 1000, 500, 100 };

            Console.WriteLine("Perf06 Example");
            Console.WriteLine();

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

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

            Console.WriteLine();

            foreach (int transSize in transactionSizes)
            {
                /* Add 50,000 rows to a table using the specified number of
                 * rows per transaction*/
                AddRows(conn, transSize);

                /* Remove all the rows in the table */
                DeleteRows(conn);
            }

            Console.WriteLine();

            /* Cleanup */
            Cleanup(conn);

            Console.WriteLine();
            Console.WriteLine("Hit <Enter> to continue");
            Console.ReadLine();
        }
    }
}