unit Sql;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  DBCtrls, ExtCtrls, Db, Grids, DBGrids, StdCtrls, ToolWin,
  ComCtrls, MSAccess, DBAccess, SdacVcl, Buttons,
  DemoFrame, SdacDemoForm, OLEDBAccess, ActiveX;

type
  TSqlFrame = class(TDemoFrame)
    ToolBar: TPanel;
    meSQL: TMemo;
    MSSQL: TMSSQL;
    Label1: TLabel;
    Splitter1: TSplitter;
    meResult: TMemo;
    btExecute: TSpeedButton;
    btBreakExec: TSpeedButton;
    Panel1: TPanel;
    cbNonBlocking: TCheckBox;
    btExecInThread: TSpeedButton;
    procedure btExecuteClick(Sender: TObject);
    procedure meSQLExit(Sender: TObject);
    procedure MSSQLAfterExecute(Sender: TObject; Result: Boolean);
    procedure cbNonBlockingClick(Sender: TObject);
    procedure btBreakExecClick(Sender: TObject);
    procedure btExecInThreadClick(Sender: TObject);
  private
    { Private declarations }
    OldProvider: TOLEDBProvider;
    DoNotRemind: boolean;
    FExecThread: TThread;
    procedure AssignProperties;
    procedure TerminateThread;
  public
    destructor Destroy; override;
    // Demo management
    procedure Initialize; override;
    procedure SetDebug(Value: boolean); override;
  end;

  { TExecThread }

  TExecThread = class(TThread)
  protected
    procedure Execute; override;
    procedure Terminate;
  end;

var
  SqlFrame: TSqlFrame;

implementation

uses ComObj;

{$IFDEF CLR}
{$R *.nfm}
{$ENDIF}
{$IFDEF WIN32}
{$R *.dfm}
{$ENDIF}

procedure LogError(EMessage: string);
begin
  SqlFrame.meResult.Lines.Add('An error with the following message has beein raised during query execution:' + #13#10 + EMessage);
end;

{ TExecThread }

procedure TExecThread.Execute;
begin
  CoInitialize(nil);
  if SqlFrame.MSSQL <> nil then
    try
      SqlFrame.btBreakExec.Enabled := True;
      SqlFrame.MSSQL.Execute;
    except
      on e: Exception do begin
        LogError(e.Message);
      end;
    end;
  Terminate;
end;

procedure TExecThread.Terminate;
begin
  inherited;
  SqlFrame.btBreakExec.Enabled := False;
  CoUninitialize;
end;

{ TSqlFrame }

procedure TSqlFrame.AssignProperties;
begin
  if Trim(MSSQL.SQL.Text) <> Trim(meSQL.Lines.Text) then
    MSSQL.SQL.Assign(meSQL.Lines);
  MSSQL.NonBlocking := cbNonBlocking.Checked;
  if MSSQL.NonBlocking then
    btBreakExec.Enabled := False;
end;

procedure TSqlFrame.TerminateThread;
begin
  if FExecThread <> nil then begin
    FExecThread.Terminate;
    MSSQL.BreakExec;
    FExecThread.WaitFor;
    FExecThread.Free;
    FExecThread := nil;
  end;
end;

procedure TSqlFrame.btExecuteClick(Sender: TObject);
begin
  AssignProperties;
  meResult.Lines.Clear;
  SdacForm.StatusBar.Panels[2].Text := 'Executing...';
  if MSSQL.NonBlocking then
    btBreakExec.Enabled := True;
  MSSQL.Execute;
end;

procedure TSqlFrame.meSQLExit(Sender: TObject);
begin
  AssignProperties;
end;

procedure TSqlFrame.MSSQLAfterExecute(Sender: TObject; Result: Boolean);
var
  s: string;
  i: integer;
begin
  btBreakExec.Enabled := False;
  if btBreakExec.Enabled then
    btBreakExec.Enabled := False;
  if Result then
    s := 'Success' + '  (' + IntToStr(MSSQL.RowsAffected) + ' rows processed)'
  else
    s := 'Execution failed';
  SdacForm.StatusBar.Panels[2].Text := s;

  for i := 0 to MSSQL.Params.Count-1 do
    meResult.Lines.Add(MSSQL.Params[i].Name + ' = ' + MSSQL.Params[i].AsString);

  meResult.Lines.Add(s);
end;

procedure TSqlFrame.cbNonBlockingClick(Sender: TObject);
var
  oldConnect: boolean;
begin
  oldConnect := MSSQL.Connection.Connected;
  try
    if cbNonBlocking.Checked then begin
      if not DoNotRemind then begin
        MessageDlg('Note, NonBlocking mode is available only with SQL Native Client installed', mtInformation, [mbOK], 0);
        DoNotRemind := True;
      end;
      MSSQL.Connection.Disconnect;
      OldProvider := MSSQL.Connection.Options.Provider;
      MSSQL.Connection.Options.Provider := prNativeClient;
    end
    else
      MSSQL.Connection.Options.Provider := OldProvider;
    MSSQL.NonBlocking := cbNonBlocking.Checked;
  finally
    cbNonBlocking.Checked := MSSQL.NonBlocking;
  end;
  MSSQL.Connection.Connected := oldConnect;
end;

procedure TSqlFrame.btBreakExecClick(Sender: TObject);
begin
  MSSQL.BreakExec;
end;

destructor TSqlFrame.Destroy;
begin
  TerminateThread;
  if (self <> nil) and MSSQL.Executing then
    MSSQL.BreakExec;
    
  inherited;
end;

procedure TSqlFrame.btExecInThreadClick(Sender: TObject);
begin
  MSSQL.SQL := meSQL.Lines;
  SDACForm.StatusBar.Panels[2].Text := 'Executing...';
  meResult.Lines.Clear;
  TerminateThread;
  FExecThread := TExecThread.Create(False)
end;

// Demo management
procedure TSqlFrame.Initialize;
begin
  inherited;
  
  FExecThread := nil;
  SqlFrame := Self;
  DoNotRemind := False;
  MSSQL.Connection := Connection as TMSConnection;
  meSQL.Lines := MSSQL.SQL;
end;

procedure TSqlFrame.SetDebug(Value: boolean);
begin
  MSSQL.Debug := Value;
end;

end.
