{ DISQLite3 example project to allow playing with transactions and view their
  effect on insert performance and hard disk activity.

  This demo uses a TTimer to trigger continuous database INSERTs of random data.
  Checking "Use Transaction" wraps inserts by a transaction. The transaction
  will automatically be commited and a new one started every Max number INSERTs
  or after a timeout period. Both values can be adjusted at runtime to view
  their effect on hard disk activity (watch the HDD control LED).

  NOTE: Because of the limited TTimer.Interval and trigger frequency, the timer
  does not even nearly match up to the full INSERT capabilities of DISQLite3.
  For truely fast performance use run this demo in "Boost" mode.

  The source code in DISQLite3_Log_Inserts_DB.pas will hopefully also serve as
  an example for how to implement fast, resource efficient logging with
  DISQLite3.

  Visit the DISQLite3 Internet site for latest information and updates:

    http://www.yunqa.de/delphi/

  Copyright (c) 2007-2009 Ralf Junker, The Delphi Inspiration <delphi@yunqa.de>

------------------------------------------------------------------------------ }

unit DISQLite3_Log_Inserts_fMain;

{$I DI.inc}
{$I DISQLite3.inc}

interface

uses
  Classes, Controls, Forms, StdCtrls, ComCtrls, ExtCtrls,
  DISQLite3_Log_Inserts_DB;

type
  TfrmLogInserts = class(TForm)
    Timer: TTimer;
    btnStartTimer: TButton;
    tbTimerInterval: TTrackBar;
    lblTimerInterval: TLabel;
    ProgressBar: TProgressBar;
    StatusBar: TStatusBar;
    gbTransactionControl: TGroupBox;
    lblTransactionTimeout: TLabel;
    lblTransactionInsertCountMax: TLabel;
    tbTransactionTimeout: TTrackBar;
    tbTransactionInsertCountMax: TTrackBar;
    cbxUseTransaction: TCheckBox;
    btnStartBoost: TButton;
    procedure Form_Create(Sender: TObject);
    procedure tbTimerInterval_Change(Sender: TObject);
    procedure btnStartTimer_Click(Sender: TObject);
    procedure tbTransactionTimeout_Change(Sender: TObject);
    procedure tbTransactionInsertCountMax_Change(Sender: TObject);
    procedure Timer_Timer(Sender: TObject);
    procedure cbxUseTransaction_Click(Sender: TObject);
    procedure btnStartBoost_Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  private
    FDatabase: TLogInsertsDB;
    FInsertCount: Integer;
    FBoost: Boolean;
    procedure InsertRecord;
  end;

const
  APP_TITLE = 'DISQLite3' + {$IFDEF DISQLite3_Personal} ' Personal' + {$ENDIF} ': Log Inserts Demo';

var
  frmLogInserts: TfrmLogInserts;

implementation

uses
  SysUtils, DISQLite3Api;

{$R *.dfm}

procedure TfrmLogInserts.Form_Create(Sender: TObject);
begin
  Caption := APP_TITLE;

  FDatabase := TLogInsertsDB.Create(Self);
  FDatabase.DatabaseName := ChangeFileExt(ParamStr(0), '.db3');
  try
    FDatabase.Open;
  except
    FDatabase.CreateDatabase;
  end;

  cbxUseTransaction.Checked := FDatabase.UseTransaction;
  cbxUseTransaction_Click(nil);
  tbTransactionInsertCountMax.Position := FDatabase.TransactionInsertCountMax;
  tbTransactionTimeout.Position := FDatabase.TransactionTimeOut;

  tbTimerInterval.Position := Timer.Interval;
end;

//------------------------------------------------------------------------------

procedure TfrmLogInserts.FormDestroy(Sender: TObject);
begin
  FDatabase.Free;
end;

//------------------------------------------------------------------------------

procedure TfrmLogInserts.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  { Make sure app can close even while in boost mode. }
  FBoost := False;
end;

procedure TfrmLogInserts.cbxUseTransaction_Click(Sender: TObject);
var
  b: Boolean;
begin
  b := cbxUseTransaction.Checked;

  lblTransactionTimeout.Enabled := b;
  tbTransactionTimeout.Enabled := b;

  lblTransactionInsertCountMax.Enabled := b;
  tbTransactionInsertCountMax.Enabled := b;

  FDatabase.UseTransaction := b;
end;

//------------------------------------------------------------------------------

procedure TfrmLogInserts.tbTimerInterval_Change(Sender: TObject);
var
  i: Integer;
begin
  i := tbTimerInterval.Position;
  Timer.Interval := i;
  lblTimerInterval.Caption := Format('Insert Interval (milliseconds): %d', [i]);
end;

//------------------------------------------------------------------------------

procedure TfrmLogInserts.tbTransactionTimeout_Change(Sender: TObject);
var
  i: Integer;
begin
  i := tbTransactionTimeout.Position;
  FDatabase.TransactionTimeOut := i;
  lblTransactionTimeout.Caption := Format('Transaction Timeout (milliseconds): %d', [i]);
end;

//------------------------------------------------------------------------------

procedure TfrmLogInserts.tbTransactionInsertCountMax_Change(Sender: TObject);
var
  i: Integer;
begin
  i := tbTransactionInsertCountMax.Position;
  FDatabase.TransactionInsertCountMax := i;
  lblTransactionInsertCountMax.Caption := Format('Maximum Number of Inserts per Transaction: %d', [i]);
end;

//------------------------------------------------------------------------------

procedure TfrmLogInserts.btnStartTimer_Click(Sender: TObject);
const
  BTN_CAPTION: array[Boolean] of string = ('Stop Timer', 'Start Timer');
var
  b: Boolean;
begin
  Timer.Enabled := not Timer.Enabled;

  b := not Timer.Enabled;
  btnStartTimer.Caption := BTN_CAPTION[b];
  btnStartBoost.Enabled := b;
end;

//------------------------------------------------------------------------------

procedure TfrmLogInserts.Timer_Timer(Sender: TObject);
begin
  InsertRecord;
end;

//------------------------------------------------------------------------------

procedure TfrmLogInserts.btnStartBoost_Click(Sender: TObject);
const
  BTN_CAPTION: array[Boolean] of string = ('Stop Boost', 'Start Boost');
var
  b: Boolean;
begin
  FBoost := not FBoost;

  b := not FBoost;
  btnStartBoost.Caption := BTN_CAPTION[b];
  lblTimerInterval.Enabled := b;
  tbTimerInterval.Enabled := b;
  btnStartTimer.Enabled := b;

  if FBoost then
    repeat
      InsertRecord;
    until not FBoost;
end;

//------------------------------------------------------------------------------

procedure TfrmLogInserts.InsertRecord;
begin
  { Insert one record. }
  FDatabase.Insert('Log ' + IntToStr(Random(MaxInt)), Random(MaxInt), Random * 1000000);
  { Update progress info. }
  Inc(FInsertCount);
  ProgressBar.Position := FInsertCount mod ProgressBar.Max;
  StatusBar.Panels[0].Text := Format('%d Inserts', [FInsertCount]);
  StatusBar.Panels[1].Text := Format('%d Commits', [FDatabase.CommitCount]);
  { Stay responsive. }
  Application.ProcessMessages;
end;

initialization
  { Initialize the DISQLite3 library prior to using any other DISQLite3
    functionality. See also sqlite3_shutdown() below.}
  sqlite3_initialize;

finalization
  { Deallocate any resources that were allocated by
    sqlite3_initialize() above. }
  sqlite3_shutdown;

end.

