home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 September
/
Chip_2001-09_cd1.bin
/
zkuste
/
delphi
/
kolekce
/
d6
/
RX275D6.ZIP
/
Units
/
Rxquery.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
2001-06-24
|
28KB
|
1,079 lines
{*******************************************************}
{ }
{ Delphi VCL Extensions (RX) }
{ }
{ Copyright (c) 1995, 1996 AO ROSNO }
{ Copyright (c) 1997 Master-Bank }
{ }
{*******************************************************}
unit RxQuery;
{$I RX.INC}
{$P+,W-,R-}
interface
uses Bde, Windows, RTLConsts, Classes, SysUtils, DB, DBTables, rxStrUtils, BdeUtils;
{.$DEFINE DEBUG}
const
DefaultMacroChar = '%';
DefaultTermChar = '/';
{ TRxQuery }
type
TQueryOpenStatus = (qsOpened, qsExecuted, qsFailed);
TRxQuery = class(TQuery)
private
FDisconnectExpected: Boolean;
FSaveQueryChanged: TNotifyEvent;
FMacroChar: Char;
FMacros: TParams;
FSQLPattern: TStrings;
FStreamPatternChanged: Boolean;
FPatternChanged: Boolean;
FOpenStatus: TQueryOpenStatus;
{$IFNDEF WIN32}
FParamCheck: Boolean;
{$ENDIF}
function GetMacros: TParams;
procedure SetMacros(Value: TParams);
procedure SetSQL(Value: TStrings);
procedure PatternChanged(Sender: TObject);
procedure QueryChanged(Sender: TObject);
procedure RecreateMacros;
procedure CreateMacros(List: TParams; const Value: PChar);
procedure Expand(Query: TStrings);
function GetMacroCount: Word;
procedure SetMacroChar(Value: Char);
function GetRealSQL: TStrings;
{$IFDEF DEBUG}
procedure SetRealSQL(Value: TStrings);
{$ENDIF DEBUG}
protected
{$IFDEF RX_D3}
procedure InternalFirst; override;
function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;
{$ENDIF}
procedure Loaded; override;
function CreateHandle: HDBICur; override;
procedure OpenCursor {$IFDEF RX_D3} (InfoQuery: Boolean) {$ENDIF}; override;
procedure Disconnect; override;
{$IFDEF RX_D5}
protected
{ IProviderSupport }
procedure PSExecute; override;
function PSGetDefaultOrder: TIndexDef; override;
function PSGetTableName: string; override;
{$ENDIF}
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure ExpandMacros;
procedure ExecSQL;
procedure Prepare;
procedure OpenOrExec(ChangeLive: Boolean);
procedure ExecDirect;
function MacroByName(const Value: string): TParam;
{$IFNDEF RX_D3}
function IsEmpty: Boolean;
{$ENDIF RX_D3}
property MacroCount: Word read GetMacroCount;
property OpenStatus: TQueryOpenStatus read FOpenStatus;
{$IFNDEF DEBUG}
property RealSQL: TStrings read GetRealSQL;
{$ENDIF DEBUG}
published
{$IFNDEF WIN32}
property ParamCheck: Boolean read FParamCheck write FParamCheck default True;
{$ENDIF}
property MacroChar: Char read FMacroChar write SetMacroChar default DefaultMacroChar;
property SQL: TStrings read FSQLPattern write SetSQL;
{$IFDEF DEBUG}
property RealSQL: TStrings read GetRealSQL write SetRealSQL stored False;
{$ENDIF DEBUG}
property Macros: TParams read GetMacros write SetMacros;
end;
{$IFDEF WIN32}
{ TRxQueryThread }
TRunQueryMode = (rqOpen, rqExecute, rqExecDirect, rqOpenOrExec);
TRxQueryThread = class(TThread)
private
FData: TBDEDataSet;
FMode: TRunQueryMode;
FPrepare: Boolean;
FException: TObject;
procedure DoHandleException;
protected
procedure ModeError; virtual;
procedure DoTerminate; override;
procedure Execute; override;
procedure HandleException; virtual;
public
constructor Create(Data: TBDEDataSet; RunMode: TRunQueryMode;
Prepare, CreateSuspended: Boolean);
end;
{$ENDIF WIN32}
{ TSQLScript }
TScriptAction = (saFail, saAbort, saRetry, saIgnore, saContinue);
TScriptErrorEvent = procedure(Sender: TObject; E: EDatabaseError;
LineNo, StatementNo: Integer; var Action: TScriptAction) of object;
TSQLScript = class(TComponent)
private
FSQL: TStrings;
FParams: TParams;
FQuery: TRxQuery;
FTransaction: Boolean;
FSemicolonTerm: Boolean;
FIgnoreParams: Boolean;
FTerm: Char;
FBeforeExec: TNotifyEvent;
FAfterExec: TNotifyEvent;
FOnScriptError: TScriptErrorEvent;
{$IFDEF WIN32}
function GetSessionName: string;
procedure SetSessionName(const Value: string);
function GetDBSession: TSession;
function GetText: string;
{$ENDIF WIN32}
{$IFDEF RX_D4}
procedure ReadParamData(Reader: TReader);
procedure WriteParamData(Writer: TWriter);
{$ENDIF RX_D4}
function GetDatabase: TDatabase;
function GetDatabaseName: string;
procedure SetDatabaseName(const Value: string);
procedure CreateParams(List: TParams; const Value: PChar);
procedure QueryChanged(Sender: TObject);
procedure SetQuery(Value: TStrings);
procedure SetParamsList(Value: TParams);
function GetParamsCount: Cardinal;
protected
{$IFDEF RX_D4}
procedure DefineProperties(Filer: TFiler); override;
{$ENDIF RX_D4}
procedure CheckExecQuery(LineNo, StatementNo: Integer);
procedure ExecuteScript(StatementNo: Integer); virtual;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure ExecSQL;
procedure ExecStatement(StatementNo: Integer);
function ParamByName(const Value: string): TParam;
{$IFDEF WIN32}
property DBSession: TSession read GetDBSession;
property Text: string read GetText;
{$ELSE}
function GetText: PChar;
{$ENDIF WIN32}
property Database: TDatabase read GetDatabase;
property ParamCount: Cardinal read GetParamsCount;
published
property DatabaseName: string read GetDatabaseName write SetDatabaseName;
property IgnoreParams: Boolean read FIgnoreParams write FIgnoreParams default False;
property SemicolonTerm: Boolean read FSemicolonTerm write FSemicolonTerm default True;
{$IFDEF WIN32}
property SessionName: string read GetSessionName write SetSessionName;
{$ENDIF WIN32}
property Term: Char read FTerm write FTerm default DefaultTermChar;
property SQL: TStrings read FSQL write SetQuery;
property Params: TParams read FParams write SetParamsList {$IFDEF RX_D4} stored False {$ENDIF};
property Transaction: Boolean read FTransaction write FTransaction;
property BeforeExec: TNotifyEvent read FBeforeExec write FBeforeExec;
property AfterExec: TNotifyEvent read FAfterExec write FAfterExec;
property OnScriptError: TScriptErrorEvent read FOnScriptError write FOnScriptError;
end;
const
dbfExecScript = dbfTable;
procedure CreateQueryParams(List: TParams; const Value: PChar; Macro: Boolean;
SpecialChar: Char; Delims: TCharSet);
implementation
uses DBUtils, Consts, DBConsts, Forms {$IFDEF RX_D3}, BDEConst {$ENDIF}
{$IFNDEF WIN32}, Str16 {$ENDIF}, VclUtils;
{ Parse SQL utility routines }
function NameDelimiter(C: Char; Delims: TCharSet): Boolean;
begin
Result := (C in [' ', ',', ';', ')', #13, #10]) or (C in Delims);
end;
function IsLiteral(C: Char): Boolean;
begin
Result := C in ['''', '"'];
end;
procedure CreateQueryParams(List: TParams; const Value: PChar; Macro: Boolean;
SpecialChar: Char; Delims: TCharSet);
var
CurPos, StartPos: PChar;
CurChar: Char;
Literal: Boolean;
EmbeddedLiteral: Boolean;
Name: string;
function StripLiterals(Buffer: PChar): string;
var
Len: Word;
TempBuf: PChar;
procedure StripChar(Value: Char);
begin
if TempBuf^ = Value then
StrMove(TempBuf, TempBuf + 1, Len - 1);
if TempBuf[StrLen(TempBuf) - 1] = Value then
TempBuf[StrLen(TempBuf) - 1] := #0;
end;
begin
Len := StrLen(Buffer) + 1;
TempBuf := AllocMem(Len);
Result := '';
try
StrCopy(TempBuf, Buffer);
StripChar('''');
StripChar('"');
Result := StrPas(TempBuf);
finally
FreeMem(TempBuf, Len);
end;
end;
begin
if SpecialChar = #0 then Exit;
CurPos := Value;
Literal := False;
EmbeddedLiteral := False;
repeat
CurChar := CurPos^;
if (CurChar = SpecialChar) and not Literal and ((CurPos + 1)^ <> SpecialChar) then
begin
StartPos := CurPos;
while (CurChar <> #0) and (Literal or not NameDelimiter(CurChar, Delims)) do begin
Inc(CurPos);
CurChar := CurPos^;
if IsLiteral(CurChar) then begin
Literal := Literal xor True;
if CurPos = StartPos + 1 then EmbeddedLiteral := True;
end;
end;
CurPos^ := #0;
if EmbeddedLiteral then begin
Name := StripLiterals(StartPos + 1);
EmbeddedLiteral := False;
end
else Name := StrPas(StartPos + 1);
if Assigned(List) then begin
{$IFDEF RX_D4}
if List.FindParam(Name) = nil then begin
{$ENDIF RX_D4}
if Macro then
List.CreateParam(ftString, Name, ptInput).AsString := TrueExpr
else List.CreateParam(ftUnknown, Name, ptUnknown);
{$IFDEF RX_D4}
end;
{$ENDIF RX_D4}
end;
CurPos^ := CurChar;
StartPos^ := '?';
Inc(StartPos);
StrMove(StartPos, CurPos, StrLen(CurPos) + 1);
CurPos := StartPos;
end
else if (CurChar = SpecialChar) and not Literal and ((CurPos + 1)^ = SpecialChar) then
StrMove(CurPos, CurPos + 1, StrLen(CurPos) + 1)
else if IsLiteral(CurChar) then Literal := Literal xor True;
Inc(CurPos);
until CurChar = #0;
end;
{ TRxQuery }
constructor TRxQuery.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
{$IFNDEF WIN32}
FParamCheck := True;
{$ENDIF WIN32}
FOpenStatus := qsFailed;
FSaveQueryChanged := TStringList(inherited SQL).OnChange;
TStringList(inherited SQL).OnChange := QueryChanged;
FMacroChar := DefaultMacroChar;
FSQLPattern := TStringList.Create;
TStringList(SQL).OnChange := PatternChanged;
FMacros := TParams.Create{$IFDEF RX_D4}(Self){$ENDIF};
end;
destructor TRxQuery.Destroy;
begin
Destroying;
Disconnect;
FMacros.Free;
FSQLPattern.Free;
inherited Destroy;
end;
procedure TRxQuery.Loaded;
begin
inherited Loaded;
GetMacros; {!! trying this way}
end;
{$IFDEF RX_D3}
procedure TRxQuery.InternalFirst;
begin
if not (UniDirectional and BOF) then
inherited InternalFirst;
end;
function TRxQuery.GetRecord(Buffer: PChar; GetMode: TGetMode;
DoCheck: Boolean): TGetResult;
begin
//!!!!!!
if UniDirectional and (GetMode in [gmPrior, gmNext]) then DoCheck := False;
Result := inherited GetRecord(Buffer, GetMode, DoCheck);
end;
{$ENDIF}
function TRxQuery.CreateHandle: HDBICur;
begin
FOpenStatus := qsFailed;
Result := inherited CreateHandle;
if Result = nil then FOpenStatus := qsExecuted
else FOpenStatus := qsOpened;
end;
procedure TRxQuery.OpenCursor;
begin
ExpandMacros;
inherited OpenCursor{$IFDEF RX_D3}(InfoQuery){$ENDIF};
end;
procedure TRxQuery.ExecSQL;
begin
ExpandMacros;
inherited ExecSQL;
end;
procedure TRxQuery.Prepare;
begin
ExpandMacros;
inherited Prepare;
end;
procedure TRxQuery.OpenOrExec(ChangeLive: Boolean);
procedure TryOpen;
begin
try
Open;
except
if OpenStatus <> qsExecuted then raise;
end;
end;
begin
try
TryOpen;
except
on E: EDatabaseError do
if RequestLive and ChangeLive then begin
RequestLive := False;
try
TryOpen;
except
on E: EDatabaseError do
if OpenStatus <> qsOpened then
ExecDirect
else begin
FOpenStatus := qsFailed;
raise;
end;
else raise;
end;
end
else begin
if OpenStatus <> qsOpened then
ExecDirect
else begin
FOpenStatus := qsFailed;
raise;
end;
end;
else raise;
end;
end;
procedure TRxQuery.ExecDirect;
{$IFNDEF WIN32}
var
P: PChar;
{$ENDIF}
begin
CheckInactive;
SetDBFlag(dbfExecSQL, True);
try
if SQL.Count > 0 then begin
FOpenStatus := qsFailed;
{$IFDEF WIN32}
Check(DbiQExecDirect(DBHandle, qryLangSQL, PChar(inherited SQL.Text),
nil));
{$ELSE}
P := inherited SQL.GetText;
try
Check(DbiQExecDirect(DBHandle, qryLangSQL, P, nil));
finally
StrDispose(P);
end;
{$ENDIF WIN32}
FOpenStatus := qsExecuted;
end
else _DBError(SEmptySQLStatement);
finally
SetDBFlag(dbfExecSQL, False);
end;
end;
procedure TRxQuery.Disconnect;
var
Strings: TStrings;
Event1, Event2: TNotifyEvent;
begin
inherited Disconnect;
if (csDestroying in ComponentState) then Exit;
Strings := inherited SQL;
Event1 := TStringList(Strings).OnChange;
Event2 := QueryChanged;
if @Event1 <> @Event2 then begin
if not FDisconnectExpected then SQL := inherited SQL;
TStringList(inherited SQL).OnChange := QueryChanged;
end;
end;
procedure TRxQuery.SetMacroChar(Value: Char);
begin
if Value <> FMacroChar then begin
FMacroChar := Value;
RecreateMacros;
end;
end;
function TRxQuery.GetMacros: TParams;
begin
if FStreamPatternChanged then begin
FStreamPatternChanged := False;
PatternChanged(nil);
end;
Result := FMacros;
end;
procedure TRxQuery.SetMacros(Value: TParams);
begin
FMacros.AssignValues(Value);
end;
procedure TRxQuery.SetSQL(Value: TStrings);
begin
inherited Disconnect;
TStringList(FSQLPattern).OnChange := nil;
FSQLPattern.Assign(Value);
TStringList(FSQLPattern).OnChange := PatternChanged;
PatternChanged(nil);
end;
procedure TRxQuery.PatternChanged(Sender: TObject);
begin
if (csLoading in ComponentState) then begin
FStreamPatternChanged := True;
Exit;
end;
inherited Disconnect;
RecreateMacros;
FPatternChanged := True;
try
ExpandMacros;
finally
FPatternChanged := False;
end;
end;
procedure TRxQuery.QueryChanged(Sender: TObject);
{$IFNDEF WIN32}
var
List: TParams;
SaveParams: Boolean;
{$ENDIF}
begin
{$IFDEF WIN32}
FSaveQueryChanged(Sender);
{$ELSE}
SaveParams := not (ParamCheck or (csDesigning in ComponentState));
if SaveParams then List := TParams.Create{$IFDEF RX_D4}(Self){$ENDIF};
try
if SaveParams then List.Assign(Params);
FSaveQueryChanged(Sender);
if SaveParams then Params.Assign(List);
finally
if SaveParams then List.Free;
end;
{$ENDIF WIN32}
if not FDisconnectExpected then begin
SQL := inherited SQL;
end;
end;
procedure TRxQuery.ExpandMacros;
var
ExpandedSQL: TStringList;
begin
if not FPatternChanged and not FStreamPatternChanged and
(MacroCount = 0) then Exit;
ExpandedSQL := TStringList.Create;
try
Expand(ExpandedSQL);
FDisconnectExpected := True;
try
inherited SQL := ExpandedSQL;
finally
FDisconnectExpected := False;
end;
finally
ExpandedSQL.Free;
end;
end;
procedure TRxQuery.RecreateMacros;
var
List: TParams;
{$IFNDEF WIN32}
P: PChar;
{$ENDIF}
begin
{$IFDEF RX_D4}
if not (csReading in ComponentState) then begin
{$ENDIF RX_D4}
List := TParams.Create{$IFDEF RX_D4}(Self){$ENDIF};
try
{$IFDEF WIN32}
CreateMacros(List, PChar(FSQLPattern.Text));
{$ELSE}
P := FSQLPattern.GetText;
try
CreateMacros(List, P);
finally
StrDispose(P);
end;
{$ENDIF WIN32}
List.AssignValues(FMacros);
{$IFDEF RX_D4}
FMacros.Clear;
FMacros.Assign(List);
finally
{$ELSE}
FMacros.Free;
FMacros := List;
except
{$ENDIF RX_D4}
List.Free;
end;
{$IFDEF RX_D4}
end
else begin
FMacros.Clear;
CreateMacros(FMacros, PChar(FSQLPattern.Text));
end;
{$ENDIF RX_D4}
end;
procedure TRxQuery.CreateMacros(List: TParams; const Value: PChar);
begin
CreateQueryParams(List, Value, True, MacroChar, ['.']);
end;
procedure TRxQuery.Expand(Query: TStrings);
function ReplaceString(const S: string): string;
var
I, J, P, LiteralChars: Integer;
Param: TParam;
Found: Boolean;
begin
Result := S;
for I := Macros.Count - 1 downto 0 do begin
Param := Macros[I];
if Param.DataType = ftUnknown then Continue;
repeat
P := Pos(MacroChar + Param.Name, Result);
Found := (P > 0) and ((Length(Result) = P + Length(Param.Name)) or
NameDelimiter(Result[P + Length(Param.Name) + 1], ['.']));
if Found then begin
LiteralChars := 0;
for J := 1 to P - 1 do
if IsLiteral(Result[J]) then Inc(LiteralChars);
Found := LiteralChars mod 2 = 0;
if Found then begin
Result := Copy(Result, 1, P - 1) + Param.Text + Copy(Result,
P + Length(Param.Name) + 1, MaxInt);
end;
end;
until not Found;
end;
end;
var
I: Integer;
begin
for I := 0 to FSQLPattern.Count - 1 do
Query.Add(ReplaceString(FSQLPattern[I]));
end;
function TRxQuery.GetMacroCount: Word;
begin
Result := FMacros.Count;
end;
function TRxQuery.MacroByName(const Value: string): TParam;
begin
Result := FMacros.ParamByName(Value);
end;
{$IFNDEF RX_D3}
function TRxQuery.IsEmpty: Boolean;
begin
Result := IsDataSetEmpty(Self);
end;
{$ENDIF RX_D3}
function TRxQuery.GetRealSQL: TStrings;
begin
try
ExpandMacros;
except
end;
Result := inherited SQL;
end;
{$IFDEF RX_D5}
{ TRxQuery.IProviderSupport }
function TRxQuery.PSGetDefaultOrder: TIndexDef;
begin
ExpandMacros;
Result := inherited PSGetDefaultOrder;
end;
function TRxQuery.PSGetTableName: string;
begin
ExpandMacros;
Result := inherited PSGetTableName;
end;
procedure TRxQuery.PSExecute;
begin
ExecSQL;
end;
{$ENDIF RX_D5}
{$IFDEF DEBUG}
procedure TRxQuery.SetRealSQL(Value: TStrings);
begin
end;
{$ENDIF DEBUG}
{$IFDEF WIN32}
{ TRxQueryThread }
constructor TRxQueryThread.Create(Data: TBDEDataSet; RunMode: TRunQueryMode;
Prepare, CreateSuspended: Boolean);
begin
inherited Create(True);
FData := Data;
FMode := RunMode;
FPrepare := Prepare;
FreeOnTerminate := True;
FData.DisableControls;
if not CreateSuspended then Resume;
end;
procedure TRxQueryThread.DoTerminate;
begin
Synchronize(FData.EnableControls);
inherited DoTerminate;
end;
procedure TRxQueryThread.ModeError;
begin
SysUtils.Abort;
end;
procedure TRxQueryThread.DoHandleException;
begin
if (FException is Exception) and not (FException is EAbort) then begin
if Assigned(Application.OnException) then
Application.OnException(FData, Exception(FException))
else
Application.ShowException(Exception(FException));
end;
end;
procedure TRxQueryThread.HandleException;
begin
FException := TObject(ExceptObject);
Synchronize(DoHandleException);
end;
procedure TRxQueryThread.Execute;
begin
try
if FPrepare and not (FMode in [rqExecDirect]) then begin
if FData is TRxQuery then TRxQuery(FData).Prepare
else if FData is TQuery then TQuery(FData).Prepare
else if FData is TStoredProc then TStoredProc(FData).Prepare;
end;
case FMode of
rqOpen:
FData.Open;
rqExecute:
begin
if FData is TRxQuery then TRxQuery(FData).ExecSQL
else if FData is TQuery then TQuery(FData).ExecSQL
else if FData is TStoredProc then TStoredProc(FData).ExecProc
else ModeError;
end;
rqExecDirect:
begin
if FData is TRxQuery then TRxQuery(FData).ExecDirect
else ModeError;
end;
rqOpenOrExec:
begin
if FData is TRxQuery then TRxQuery(FData).OpenOrExec(True)
else FData.Open;
end;
end;
except
HandleException;
end;
end;
{$ENDIF WIN32}
{ TSQLScript }
constructor TSQLScript.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FSQL := TStringList.Create;
TStringList(SQL).OnChange := QueryChanged;
FParams := TParams.Create{$IFDEF RX_D4}(Self){$ENDIF};
FQuery := TRxQuery.Create(Self);
FSemicolonTerm := True;
FTerm := DefaultTermChar;
end;
destructor TSQLScript.Destroy;
begin
FQuery.Free;
FSQL.Free;
FParams.Free;
inherited Destroy;
end;
function TSQLScript.GetDatabase: TDatabase;
begin
Result := FQuery.Database;
end;
function TSQLScript.GetDatabaseName: string;
begin
Result := FQuery.DatabaseName;
end;
procedure TSQLScript.SetDatabaseName(const Value: string);
begin
FQuery.DatabaseName := Value;
end;
{$IFDEF WIN32}
function TSQLScript.GetSessionName: string;
begin
Result := FQuery.SessionName;
end;
procedure TSQLScript.SetSessionName(const Value: string);
begin
FQuery.SessionName := Value;
end;
function TSQLScript.GetDBSession: TSession;
begin
Result := FQuery.DBSession;
end;
{$ENDIF WIN32}
procedure TSQLScript.CheckExecQuery(LineNo, StatementNo: Integer);
var
Done: Boolean;
Action: TScriptAction;
I: Integer;
Param: TParam;
{$IFNDEF WIN32}
Msg: array[0..255] of Char;
{$ENDIF}
S: string;
begin
Done := False;
repeat
try
if IgnoreParams then FQuery.ExecDirect
else begin
for I := 0 to FQuery.Params.Count - 1 do begin
Param := FQuery.Params[I];
Param.Assign(Params.ParamByName(Param.Name));
end;
FQuery.ExecSQL;
end;
Done := True;
except
on E: EDatabaseError do begin
Action := saFail;
S := Format(ResStr(SParseError), [ResStr(SMsgdlgError), LineNo]);
if E is EDBEngineError then
TDBError.Create(EDBEngineError(E), 0, LineNo,
{$IFDEF WIN32} PChar(S) {$ELSE} StrPCopy(Msg, S) {$ENDIF})
else begin
if E.Message <> '' then E.Message := E.Message + '. ';
E.Message := E.Message + S;
end;
if Assigned(FOnScriptError) then
FOnScriptError(Self, E, LineNo, StatementNo, Action);
if Action = saFail then raise;
if Action = saAbort then SysUtils.Abort;
if Action = saContinue then begin
Application.HandleException(Self);
Done := True;
end
else if Action = saIgnore then Done := True;
end;
end;
until Done;
end;
procedure TSQLScript.ExecuteScript(StatementNo: Integer);
var
S, LastStr: string;
IsTrans, SQLFilled, StmtFound: Boolean;
I, P, CurrStatement: Integer;
begin
IsTrans := FTransaction {$IFNDEF WIN32} and Database.IsSQLBased {$ENDIF}
and not TransActive(Database) and (StatementNo < 0);
LastStr := '';
try
if IsTrans then begin
{$IFDEF WIN32}
if not Database.IsSQLBased then
Database.TransIsolation := tiDirtyRead;
{$ENDIF}
Database.StartTransaction;
end;
except
IsTrans := False;
end;
try
I := 0;
CurrStatement := 0;
StmtFound := False;
while I < SQL.Count do begin
FQuery.SQL.BeginUpdate;
try
FQuery.SQL.Clear;
SQLFilled := False;
repeat
if LastStr <> '' then begin
FQuery.SQL.Add(LastStr);
LastStr := '';
end;
if I < SQL.Count then begin
S := Trim(SQL[I]);
Inc(I);
P := Pos(';', S);
if (P > 0) and FSemicolonTerm then begin
LastStr := Trim(Copy(S, P + 1, MaxInt));
S := Copy(S, 1, P - 1);
if S <> '' then FQuery.SQL.Add(S);
SQLFilled := True;
end
else begin
if (S = Term) then SQLFilled := True
else if S <> '' then FQuery.SQL.Add(S);
end;
end
else SQLFilled := True;
until SQLFilled;
finally
FQuery.SQL.EndUpdate;
end;
if FQuery.SQL.Count > 0 then begin
if (StatementNo < 0) or (StatementNo = CurrStatement) then begin
StmtFound := True;
CheckExecQuery(I - 1, CurrStatement);
if StatementNo = CurrStatement then Break;
end;
Inc(CurrStatement);
end;
end;
if not StmtFound then begin
{$IFDEF RX_D3}
DatabaseError(Format(SListIndexError, [StatementNo]));
{$ELSE}
DatabaseError(Format('%s: %d', [LoadStr(SListIndexError), StatementNo]));
{$ENDIF RX_D3}
end;
if IsTrans then Database.Commit;
except
if IsTrans then Database.Rollback;
raise;
end;
end;
procedure TSQLScript.ExecStatement(StatementNo: Integer);
begin
if FSQL.Count = 0 then _DBError(SEmptySQLStatement);
FQuery.SetDBFlag(dbfExecScript, True);
try
if not Database.Connected then _DBError(SDatabaseClosed);
if Assigned(FBeforeExec) then FBeforeExec(Self);
ExecuteScript(StatementNo);
if Assigned(FAfterExec) then FAfterExec(Self);
finally
FQuery.SetDBFlag(dbfExecScript, False);
end;
end;
procedure TSQLScript.ExecSQL;
begin
ExecStatement(-1);
end;
procedure TSQLScript.CreateParams(List: TParams; const Value: PChar);
begin
CreateQueryParams(List, Value, False, ':', []);
end;
procedure TSQLScript.SetQuery(Value: TStrings);
begin
TStringList(SQL).OnChange := nil;
FSQL.Assign(Value);
TStringList(SQL).OnChange := QueryChanged;
QueryChanged(nil);
end;
function TSQLScript.GetText: {$IFDEF WIN32} string {$ELSE} PChar {$ENDIF};
begin
{$IFDEF WIN32}
Result := SQL.Text;
{$ELSE}
Result := SQL.GetText;
{$ENDIF}
end;
procedure TSQLScript.QueryChanged(Sender: TObject);
var
List: TParams;
{$IFNDEF WIN32}
P: PChar;
{$ENDIF}
begin
{$IFDEF RX_D4}
if not (csReading in ComponentState) then begin
{$ENDIF RX_D4}
List := TParams.Create{$IFDEF RX_D4}(Self){$ENDIF};
try
{$IFDEF WIN32}
CreateParams(List, PChar(Text));
{$ELSE}
P := GetText;
try
CreateParams(List, P);
finally
StrDispose(P);
end;
{$ENDIF WIN32}
List.AssignValues(FParams);
{$IFDEF RX_D4}
FParams.Clear;
FParams.Assign(List);
finally
{$ELSE}
FParams.Free;
FParams := List;
except
{$ENDIF RX_D4}
List.Free;
end;
{$IFDEF RX_D4}
end
else begin
FParams.Clear;
CreateParams(FParams, PChar(Text));
end;
{$ENDIF RX_D4}
end;
function TSQLScript.ParamByName(const Value: string): TParam;
begin
Result := FParams.ParamByName(Value);
end;
procedure TSQLScript.SetParamsList(Value: TParams);
begin
FParams.AssignValues(Value);
end;
function TSQLScript.GetParamsCount: Cardinal;
begin
Result := FParams.Count;
end;
{$IFDEF RX_D4}
procedure TSQLScript.DefineProperties(Filer: TFiler);
begin
inherited DefineProperties(Filer);
Filer.DefineProperty('ParamData', ReadParamData, WriteParamData, True);
end;
procedure TSQLScript.ReadParamData(Reader: TReader);
begin
Reader.ReadValue;
Reader.ReadCollection(FParams);
end;
procedure TSQLScript.WriteParamData(Writer: TWriter);
begin
Writer.WriteCollection(Params);
end;
{$ENDIF RX_D4}
end.