Rxquery.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:27k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1995, 1996 AO ROSNO             }
  6. {         Copyright (c) 1997 Master-Bank                }
  7. {                                                       }
  8. {*******************************************************}
  9. unit RxQuery;
  10. {$I RX.INC}
  11. {$P+,W-,R-}
  12. interface
  13. uses Bde, Windows, RTLConsts,  Classes, SysUtils, DB, DBTables, rxStrUtils, BdeUtils;
  14. {.$DEFINE DEBUG}
  15. const
  16.   DefaultMacroChar = '%';
  17.   DefaultTermChar  = '/';
  18. { TRxQuery }
  19. type
  20.   TQueryOpenStatus = (qsOpened, qsExecuted, qsFailed);
  21.   TRxQuery = class(TQuery)
  22.   private
  23.     FDisconnectExpected: Boolean;
  24.     FSaveQueryChanged: TNotifyEvent;
  25.     FMacroChar: Char;
  26.     FMacros: TParams;
  27.     FSQLPattern: TStrings;
  28.     FStreamPatternChanged: Boolean;
  29.     FPatternChanged: Boolean;
  30.     FOpenStatus: TQueryOpenStatus;
  31. {$IFNDEF WIN32}
  32.     FParamCheck: Boolean;
  33. {$ENDIF}
  34.     function GetMacros: TParams;
  35.     procedure SetMacros(Value: TParams);
  36.     procedure SetSQL(Value: TStrings);
  37.     procedure PatternChanged(Sender: TObject);
  38.     procedure QueryChanged(Sender: TObject);
  39.     procedure RecreateMacros;
  40.     procedure CreateMacros(List: TParams; const Value: PChar);
  41.     procedure Expand(Query: TStrings);
  42.     function GetMacroCount: Word;
  43.     procedure SetMacroChar(Value: Char);
  44.     function GetRealSQL: TStrings;
  45. {$IFDEF DEBUG}
  46.     procedure SetRealSQL(Value: TStrings);
  47. {$ENDIF DEBUG}
  48.   protected
  49. {$IFDEF RX_D3}
  50.     procedure InternalFirst; override;
  51.     function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;
  52. {$ENDIF}
  53.     procedure Loaded; override;
  54.     function CreateHandle: HDBICur; override;
  55.     procedure OpenCursor {$IFDEF RX_D3} (InfoQuery: Boolean) {$ENDIF}; override;
  56.     procedure Disconnect; override;
  57. {$IFDEF RX_D5}
  58.   protected
  59.     { IProviderSupport }
  60.     procedure PSExecute; override;
  61.     function PSGetDefaultOrder: TIndexDef; override;
  62.     function PSGetTableName: string; override;
  63. {$ENDIF}
  64.   public
  65.     constructor Create(AOwner: TComponent); override;
  66.     destructor Destroy; override;
  67.     procedure ExpandMacros;
  68.     procedure ExecSQL;
  69.     procedure Prepare;
  70.     procedure OpenOrExec(ChangeLive: Boolean);
  71.     procedure ExecDirect;
  72.     function MacroByName(const Value: string): TParam;
  73. {$IFNDEF RX_D3}
  74.     function IsEmpty: Boolean;
  75. {$ENDIF RX_D3}
  76.     property MacroCount: Word read GetMacroCount;
  77.     property OpenStatus: TQueryOpenStatus read FOpenStatus;
  78. {$IFNDEF DEBUG}
  79.     property RealSQL: TStrings read GetRealSQL;
  80. {$ENDIF DEBUG}
  81.   published
  82. {$IFNDEF WIN32}
  83.     property ParamCheck: Boolean read FParamCheck write FParamCheck default True;
  84. {$ENDIF}
  85.     property MacroChar: Char read FMacroChar write SetMacroChar default DefaultMacroChar;
  86.     property SQL: TStrings read FSQLPattern write SetSQL;
  87. {$IFDEF DEBUG}
  88.     property RealSQL: TStrings read GetRealSQL write SetRealSQL stored False;
  89. {$ENDIF DEBUG}
  90.     property Macros: TParams read GetMacros write SetMacros;
  91.   end;
  92. {$IFDEF WIN32}
  93. { TRxQueryThread }
  94.   TRunQueryMode = (rqOpen, rqExecute, rqExecDirect, rqOpenOrExec);
  95.   TRxQueryThread = class(TThread)
  96.   private
  97.     FData: TBDEDataSet;
  98.     FMode: TRunQueryMode;
  99.     FPrepare: Boolean;
  100.     FException: TObject;
  101.     procedure DoHandleException;
  102.   protected
  103.     procedure ModeError; virtual;
  104.     procedure DoTerminate; override;
  105.     procedure Execute; override;
  106.     procedure HandleException; virtual;
  107.   public
  108.     constructor Create(Data: TBDEDataSet; RunMode: TRunQueryMode;
  109.       Prepare, CreateSuspended: Boolean);
  110.   end;
  111. {$ENDIF WIN32}
  112. { TSQLScript }
  113.   TScriptAction = (saFail, saAbort, saRetry, saIgnore, saContinue);
  114.   TScriptErrorEvent = procedure(Sender: TObject; E: EDatabaseError;
  115.     LineNo, StatementNo: Integer; var Action: TScriptAction) of object;
  116.   TSQLScript = class(TComponent)
  117.   private
  118.     FSQL: TStrings;
  119.     FParams: TParams;
  120.     FQuery: TRxQuery;
  121.     FTransaction: Boolean;
  122.     FSemicolonTerm: Boolean;
  123.     FIgnoreParams: Boolean;
  124.     FTerm: Char;
  125.     FBeforeExec: TNotifyEvent;
  126.     FAfterExec: TNotifyEvent;
  127.     FOnScriptError: TScriptErrorEvent;
  128. {$IFDEF WIN32}
  129.     function GetSessionName: string;
  130.     procedure SetSessionName(const Value: string);
  131.     function GetDBSession: TSession;
  132.     function GetText: string;
  133. {$ENDIF WIN32}
  134. {$IFDEF RX_D4}
  135.     procedure ReadParamData(Reader: TReader);
  136.     procedure WriteParamData(Writer: TWriter);
  137. {$ENDIF RX_D4}
  138.     function GetDatabase: TDatabase;
  139.     function GetDatabaseName: string;
  140.     procedure SetDatabaseName(const Value: string);
  141.     procedure CreateParams(List: TParams; const Value: PChar);
  142.     procedure QueryChanged(Sender: TObject);
  143.     procedure SetQuery(Value: TStrings);
  144.     procedure SetParamsList(Value: TParams);
  145.     function GetParamsCount: Cardinal;
  146.   protected
  147. {$IFDEF RX_D4}
  148.     procedure DefineProperties(Filer: TFiler); override;
  149. {$ENDIF RX_D4}
  150.     procedure CheckExecQuery(LineNo, StatementNo: Integer);
  151.     procedure ExecuteScript(StatementNo: Integer); virtual;
  152.   public
  153.     constructor Create(AOwner: TComponent); override;
  154.     destructor Destroy; override;
  155.     procedure ExecSQL;
  156.     procedure ExecStatement(StatementNo: Integer);
  157.     function ParamByName(const Value: string): TParam;
  158. {$IFDEF WIN32}
  159.     property DBSession: TSession read GetDBSession;
  160.     property Text: string read GetText;
  161. {$ELSE}
  162.     function GetText: PChar;
  163. {$ENDIF WIN32}
  164.     property Database: TDatabase read GetDatabase;
  165.     property ParamCount: Cardinal read GetParamsCount;
  166.   published
  167.     property DatabaseName: string read GetDatabaseName write SetDatabaseName;
  168.     property IgnoreParams: Boolean read FIgnoreParams write FIgnoreParams default False;
  169.     property SemicolonTerm: Boolean read FSemicolonTerm write FSemicolonTerm default True;
  170. {$IFDEF WIN32}
  171.     property SessionName: string read GetSessionName write SetSessionName;
  172. {$ENDIF WIN32}
  173.     property Term: Char read FTerm write FTerm default DefaultTermChar;
  174.     property SQL: TStrings read FSQL write SetQuery;
  175.     property Params: TParams read FParams write SetParamsList {$IFDEF RX_D4} stored False {$ENDIF};
  176.     property Transaction: Boolean read FTransaction write FTransaction;
  177.     property BeforeExec: TNotifyEvent read FBeforeExec write FBeforeExec;
  178.     property AfterExec: TNotifyEvent read FAfterExec write FAfterExec;
  179.     property OnScriptError: TScriptErrorEvent read FOnScriptError write FOnScriptError;
  180.   end;
  181. const
  182.   dbfExecScript = dbfTable;
  183. procedure CreateQueryParams(List: TParams; const Value: PChar; Macro: Boolean;
  184.   SpecialChar: Char; Delims: TCharSet);
  185. implementation
  186. uses DBUtils, Consts, DBConsts, Forms {$IFDEF RX_D3}, BDEConst {$ENDIF}
  187.   {$IFNDEF WIN32}, Str16 {$ENDIF}, VclUtils;
  188. { Parse SQL utility routines }
  189. function NameDelimiter(C: Char; Delims: TCharSet): Boolean;
  190. begin
  191.   Result := (C in [' ', ',', ';', ')', #13, #10]) or (C in Delims);
  192. end;
  193. function IsLiteral(C: Char): Boolean;
  194. begin
  195.   Result := C in ['''', '"'];
  196. end;
  197. procedure CreateQueryParams(List: TParams; const Value: PChar; Macro: Boolean;
  198.   SpecialChar: Char; Delims: TCharSet);
  199. var
  200.   CurPos, StartPos: PChar;
  201.   CurChar: Char;
  202.   Literal: Boolean;
  203.   EmbeddedLiteral: Boolean;
  204.   Name: string;
  205.   function StripLiterals(Buffer: PChar): string;
  206.   var
  207.     Len: Word;
  208.     TempBuf: PChar;
  209.     procedure StripChar(Value: Char);
  210.     begin
  211.       if TempBuf^ = Value then
  212.         StrMove(TempBuf, TempBuf + 1, Len - 1);
  213.       if TempBuf[StrLen(TempBuf) - 1] = Value then
  214.         TempBuf[StrLen(TempBuf) - 1] := #0;
  215.     end;
  216.   begin
  217.     Len := StrLen(Buffer) + 1;
  218.     TempBuf := AllocMem(Len);
  219.     Result := '';
  220.     try
  221.       StrCopy(TempBuf, Buffer);
  222.       StripChar('''');
  223.       StripChar('"');
  224.       Result := StrPas(TempBuf);
  225.     finally
  226.       FreeMem(TempBuf, Len);
  227.     end;
  228.   end;
  229. begin
  230.   if SpecialChar = #0 then Exit;
  231.   CurPos := Value;
  232.   Literal := False;
  233.   EmbeddedLiteral := False;
  234.   repeat
  235.     CurChar := CurPos^;
  236.     if (CurChar = SpecialChar) and not Literal and ((CurPos + 1)^ <> SpecialChar) then
  237.     begin
  238.       StartPos := CurPos;
  239.       while (CurChar <> #0) and (Literal or not NameDelimiter(CurChar, Delims)) do begin
  240.         Inc(CurPos);
  241.         CurChar := CurPos^;
  242.         if IsLiteral(CurChar) then begin
  243.           Literal := Literal xor True;
  244.           if CurPos = StartPos + 1 then EmbeddedLiteral := True;
  245.         end;
  246.       end;
  247.       CurPos^ := #0;
  248.       if EmbeddedLiteral then begin
  249.         Name := StripLiterals(StartPos + 1);
  250.         EmbeddedLiteral := False;
  251.       end
  252.       else Name := StrPas(StartPos + 1);
  253.       if Assigned(List) then begin
  254. {$IFDEF RX_D4}
  255.         if List.FindParam(Name) = nil then begin
  256. {$ENDIF RX_D4}
  257.           if Macro then
  258.             List.CreateParam(ftString, Name, ptInput).AsString := TrueExpr
  259.           else List.CreateParam(ftUnknown, Name, ptUnknown);
  260. {$IFDEF RX_D4}
  261.         end;
  262. {$ENDIF RX_D4}
  263.       end;
  264.       CurPos^ := CurChar;
  265.       StartPos^ := '?';
  266.       Inc(StartPos);
  267.       StrMove(StartPos, CurPos, StrLen(CurPos) + 1);
  268.       CurPos := StartPos;
  269.     end
  270.     else if (CurChar = SpecialChar) and not Literal and ((CurPos + 1)^ = SpecialChar) then
  271.       StrMove(CurPos, CurPos + 1, StrLen(CurPos) + 1)
  272.     else if IsLiteral(CurChar) then Literal := Literal xor True;
  273.     Inc(CurPos);
  274.   until CurChar = #0;
  275. end;
  276. { TRxQuery }
  277. constructor TRxQuery.Create(AOwner: TComponent);
  278. begin
  279.   inherited Create(AOwner);
  280. {$IFNDEF WIN32}
  281.   FParamCheck := True;
  282. {$ENDIF WIN32}
  283.   FOpenStatus := qsFailed;
  284.   FSaveQueryChanged := TStringList(inherited SQL).OnChange;
  285.   TStringList(inherited SQL).OnChange := QueryChanged;
  286.   FMacroChar := DefaultMacroChar;
  287.   FSQLPattern := TStringList.Create;
  288.   TStringList(SQL).OnChange := PatternChanged;
  289.   FMacros := TParams.Create{$IFDEF RX_D4}(Self){$ENDIF};
  290. end;
  291. destructor TRxQuery.Destroy;
  292. begin
  293.   Destroying;
  294.   Disconnect;
  295.   FMacros.Free;
  296.   FSQLPattern.Free;
  297.   inherited Destroy;
  298. end;
  299. procedure TRxQuery.Loaded;
  300. begin
  301.   inherited Loaded;
  302.   GetMacros; {!! trying this way}
  303. end;
  304. {$IFDEF RX_D3}
  305. procedure TRxQuery.InternalFirst;
  306. begin
  307.   if not (UniDirectional and BOF) then
  308.     inherited InternalFirst;
  309. end;
  310. function TRxQuery.GetRecord(Buffer: PChar; GetMode: TGetMode;
  311.   DoCheck: Boolean): TGetResult;
  312. begin
  313.   //!!!!!!
  314.   if UniDirectional and (GetMode in [gmPrior, gmNext]) then DoCheck := False;
  315.   Result := inherited GetRecord(Buffer, GetMode, DoCheck);
  316. end;
  317. {$ENDIF}
  318. function TRxQuery.CreateHandle: HDBICur;
  319. begin
  320.   FOpenStatus := qsFailed;
  321.   Result := inherited CreateHandle;
  322.   if Result = nil then FOpenStatus := qsExecuted
  323.   else FOpenStatus := qsOpened;
  324. end;
  325. procedure TRxQuery.OpenCursor;
  326. begin
  327.   ExpandMacros;
  328.   inherited OpenCursor{$IFDEF RX_D3}(InfoQuery){$ENDIF};
  329. end;
  330. procedure TRxQuery.ExecSQL;
  331. begin
  332.   ExpandMacros;
  333.   inherited ExecSQL;
  334. end;
  335. procedure TRxQuery.Prepare;
  336. begin
  337.   ExpandMacros;
  338.   inherited Prepare;
  339. end;
  340. procedure TRxQuery.OpenOrExec(ChangeLive: Boolean);
  341.   procedure TryOpen;
  342.   begin
  343.     try
  344.       Open;
  345.     except
  346.       if OpenStatus <> qsExecuted then raise;
  347.     end;
  348.   end;
  349. begin
  350.   try
  351.     TryOpen;
  352.   except
  353.     on E: EDatabaseError do
  354.       if RequestLive and ChangeLive then begin
  355.         RequestLive := False;
  356.         try
  357.           TryOpen;
  358.         except
  359.           on E: EDatabaseError do
  360.             if OpenStatus <> qsOpened then
  361.               ExecDirect
  362.             else begin
  363.               FOpenStatus := qsFailed;
  364.               raise;
  365.             end;
  366.           else raise;
  367.         end;
  368.       end
  369.       else begin
  370.         if OpenStatus <> qsOpened then
  371.           ExecDirect
  372.         else begin
  373.           FOpenStatus := qsFailed;
  374.           raise;
  375.         end;
  376.       end;
  377.     else raise;
  378.   end;
  379. end;
  380. procedure TRxQuery.ExecDirect;
  381. {$IFNDEF WIN32}
  382. var
  383.   P: PChar;
  384. {$ENDIF}
  385. begin
  386.   CheckInactive;
  387.   SetDBFlag(dbfExecSQL, True);
  388.   try
  389.     if SQL.Count > 0 then begin
  390.       FOpenStatus := qsFailed;
  391. {$IFDEF WIN32}
  392.       Check(DbiQExecDirect(DBHandle, qryLangSQL, PChar(inherited SQL.Text),
  393.         nil));
  394. {$ELSE}
  395.       P := inherited SQL.GetText;
  396.       try
  397.         Check(DbiQExecDirect(DBHandle, qryLangSQL, P, nil));
  398.       finally
  399.         StrDispose(P);
  400.       end;
  401. {$ENDIF WIN32}
  402.       FOpenStatus := qsExecuted;
  403.     end
  404.     else _DBError(SEmptySQLStatement);
  405.   finally
  406.     SetDBFlag(dbfExecSQL, False);
  407.   end;
  408. end;
  409. procedure TRxQuery.Disconnect;
  410. var
  411.   Strings: TStrings;
  412.   Event1, Event2: TNotifyEvent;
  413. begin
  414.   inherited Disconnect;
  415.   if (csDestroying in ComponentState) then Exit;
  416.   Strings := inherited SQL;
  417.   Event1 := TStringList(Strings).OnChange;
  418.   Event2 := QueryChanged;
  419.   if @Event1 <> @Event2 then begin
  420.     if not FDisconnectExpected then SQL := inherited SQL;
  421.     TStringList(inherited SQL).OnChange := QueryChanged;
  422.   end;
  423. end;
  424. procedure TRxQuery.SetMacroChar(Value: Char);
  425. begin
  426.   if Value <> FMacroChar then begin
  427.     FMacroChar := Value;
  428.     RecreateMacros;
  429.   end;
  430. end;
  431. function TRxQuery.GetMacros: TParams;
  432. begin
  433.   if FStreamPatternChanged then begin
  434.     FStreamPatternChanged := False;
  435.     PatternChanged(nil);
  436.   end;
  437.   Result := FMacros;
  438. end;
  439. procedure TRxQuery.SetMacros(Value: TParams);
  440. begin
  441.   FMacros.AssignValues(Value);
  442. end;
  443. procedure TRxQuery.SetSQL(Value: TStrings);
  444. begin
  445.   inherited Disconnect;
  446.   TStringList(FSQLPattern).OnChange := nil;
  447.   FSQLPattern.Assign(Value);
  448.   TStringList(FSQLPattern).OnChange := PatternChanged;
  449.   PatternChanged(nil);
  450. end;
  451. procedure TRxQuery.PatternChanged(Sender: TObject);
  452. begin
  453.   if (csLoading in ComponentState) then begin
  454.     FStreamPatternChanged := True;
  455.     Exit;
  456.   end;
  457.   inherited Disconnect;
  458.   RecreateMacros;
  459.   FPatternChanged := True;
  460.   try
  461.     ExpandMacros;
  462.   finally
  463.     FPatternChanged := False;
  464.   end;
  465. end;
  466. procedure TRxQuery.QueryChanged(Sender: TObject);
  467. {$IFNDEF WIN32}
  468. var
  469.   List: TParams;
  470.   SaveParams: Boolean;
  471. {$ENDIF}
  472. begin
  473. {$IFDEF WIN32}
  474.   FSaveQueryChanged(Sender);
  475. {$ELSE}
  476.   SaveParams := not (ParamCheck or (csDesigning in ComponentState));
  477.   if SaveParams then List := TParams.Create{$IFDEF RX_D4}(Self){$ENDIF};
  478.   try
  479.     if SaveParams then List.Assign(Params);
  480.     FSaveQueryChanged(Sender);
  481.     if SaveParams then Params.Assign(List);
  482.   finally
  483.     if SaveParams then List.Free;
  484.   end;
  485. {$ENDIF WIN32}
  486.   if not FDisconnectExpected then begin
  487.     SQL := inherited SQL;
  488.   end;
  489. end;
  490. procedure TRxQuery.ExpandMacros;
  491. var
  492.   ExpandedSQL: TStringList;
  493. begin
  494.   if not FPatternChanged and not FStreamPatternChanged and
  495.     (MacroCount = 0) then Exit;
  496.   ExpandedSQL := TStringList.Create;
  497.   try
  498.     Expand(ExpandedSQL);
  499.     FDisconnectExpected := True;
  500.     try
  501.       inherited SQL := ExpandedSQL;
  502.     finally
  503.       FDisconnectExpected := False;
  504.     end;
  505.   finally
  506.     ExpandedSQL.Free;
  507.   end;
  508. end;
  509. procedure TRxQuery.RecreateMacros;
  510. var
  511.   List: TParams;
  512. {$IFNDEF WIN32}
  513.   P: PChar;
  514. {$ENDIF}
  515. begin
  516. {$IFDEF RX_D4}
  517.   if not (csReading in ComponentState) then begin
  518. {$ENDIF RX_D4}
  519.     List := TParams.Create{$IFDEF RX_D4}(Self){$ENDIF};
  520.     try
  521.   {$IFDEF WIN32}
  522.       CreateMacros(List, PChar(FSQLPattern.Text));
  523.   {$ELSE}
  524.       P := FSQLPattern.GetText;
  525.       try
  526.         CreateMacros(List, P);
  527.       finally
  528.         StrDispose(P);
  529.       end;
  530.   {$ENDIF WIN32}
  531.       List.AssignValues(FMacros);
  532.   {$IFDEF RX_D4}
  533.       FMacros.Clear;
  534.       FMacros.Assign(List);
  535.     finally
  536.   {$ELSE}
  537.       FMacros.Free;
  538.       FMacros := List;
  539.     except
  540.   {$ENDIF RX_D4}
  541.       List.Free;
  542.     end;
  543. {$IFDEF RX_D4}
  544.   end
  545.   else begin
  546.     FMacros.Clear;
  547.     CreateMacros(FMacros, PChar(FSQLPattern.Text));
  548.   end;
  549. {$ENDIF RX_D4}
  550. end;
  551. procedure TRxQuery.CreateMacros(List: TParams; const Value: PChar);
  552. begin
  553.   CreateQueryParams(List, Value, True, MacroChar, ['.']);
  554. end;
  555. procedure TRxQuery.Expand(Query: TStrings);
  556.   function ReplaceString(const S: string): string;
  557.   var
  558.     I, J, P, LiteralChars: Integer;
  559.     Param: TParam;
  560.     Found: Boolean;
  561.   begin
  562.     Result := S;
  563.     for I := Macros.Count - 1 downto 0 do begin
  564.       Param := Macros[I];
  565.       if Param.DataType = ftUnknown then Continue;
  566.       repeat
  567.         P := Pos(MacroChar + Param.Name, Result);
  568.         Found := (P > 0) and ((Length(Result) = P + Length(Param.Name)) or
  569.           NameDelimiter(Result[P + Length(Param.Name) + 1], ['.']));
  570.         if Found then begin
  571.           LiteralChars := 0;
  572.           for J := 1 to P - 1 do
  573.             if IsLiteral(Result[J]) then Inc(LiteralChars);
  574.           Found := LiteralChars mod 2 = 0;
  575.           if Found then begin
  576.             Result := Copy(Result, 1, P - 1) + Param.Text + Copy(Result,
  577.               P + Length(Param.Name) + 1, MaxInt);
  578.           end;
  579.         end;
  580.       until not Found;
  581.     end;
  582.   end;
  583. var
  584.   I: Integer;
  585. begin
  586.   for I := 0 to FSQLPattern.Count - 1 do
  587.     Query.Add(ReplaceString(FSQLPattern[I]));
  588. end;
  589. function TRxQuery.GetMacroCount: Word;
  590. begin
  591.   Result := FMacros.Count;
  592. end;
  593. function TRxQuery.MacroByName(const Value: string): TParam;
  594. begin
  595.   Result := FMacros.ParamByName(Value);
  596. end;
  597. {$IFNDEF RX_D3}
  598. function TRxQuery.IsEmpty: Boolean;
  599. begin
  600.   Result := IsDataSetEmpty(Self);
  601. end;
  602. {$ENDIF RX_D3}
  603. function TRxQuery.GetRealSQL: TStrings;
  604. begin
  605.   try
  606.     ExpandMacros;
  607.   except
  608.   end;
  609.   Result := inherited SQL;
  610. end;
  611. {$IFDEF RX_D5}
  612. { TRxQuery.IProviderSupport }
  613. function TRxQuery.PSGetDefaultOrder: TIndexDef;
  614. begin
  615.   ExpandMacros;
  616.   Result := inherited PSGetDefaultOrder;
  617. end;
  618. function TRxQuery.PSGetTableName: string;
  619. begin
  620.   ExpandMacros;
  621.   Result := inherited PSGetTableName;
  622. end;
  623. procedure TRxQuery.PSExecute;
  624. begin
  625.   ExecSQL;
  626. end;
  627. {$ENDIF RX_D5}
  628. {$IFDEF DEBUG}
  629. procedure TRxQuery.SetRealSQL(Value: TStrings);
  630. begin
  631. end;
  632. {$ENDIF DEBUG}
  633. {$IFDEF WIN32}
  634. { TRxQueryThread }
  635. constructor TRxQueryThread.Create(Data: TBDEDataSet; RunMode: TRunQueryMode;
  636.   Prepare, CreateSuspended: Boolean);
  637. begin
  638.   inherited Create(True);
  639.   FData := Data;
  640.   FMode := RunMode;
  641.   FPrepare := Prepare;
  642.   FreeOnTerminate := True;
  643.   FData.DisableControls;
  644.   if not CreateSuspended then Resume;
  645. end;
  646. procedure TRxQueryThread.DoTerminate;
  647. begin
  648.   Synchronize(FData.EnableControls);
  649.   inherited DoTerminate;
  650. end;
  651. procedure TRxQueryThread.ModeError;
  652. begin
  653.   SysUtils.Abort;
  654. end;
  655. procedure TRxQueryThread.DoHandleException;
  656. begin
  657.   if (FException is Exception) and not (FException is EAbort) then begin
  658.     if Assigned(Application.OnException) then
  659.       Application.OnException(FData, Exception(FException))
  660.     else
  661.       Application.ShowException(Exception(FException));
  662.   end;
  663. end;
  664. procedure TRxQueryThread.HandleException;
  665. begin
  666.   FException := TObject(ExceptObject);
  667.   Synchronize(DoHandleException);
  668. end;
  669. procedure TRxQueryThread.Execute;
  670. begin
  671.   try
  672.     if FPrepare and not (FMode in [rqExecDirect]) then begin
  673.       if FData is TRxQuery then TRxQuery(FData).Prepare
  674.       else if FData is TQuery then TQuery(FData).Prepare
  675.       else if FData is TStoredProc then TStoredProc(FData).Prepare;
  676.     end;
  677.     case FMode of
  678.       rqOpen:
  679.         FData.Open;
  680.       rqExecute:
  681.         begin
  682.           if FData is TRxQuery then TRxQuery(FData).ExecSQL
  683.           else if FData is TQuery then TQuery(FData).ExecSQL
  684.           else if FData is TStoredProc then TStoredProc(FData).ExecProc
  685.           else ModeError;
  686.         end;
  687.       rqExecDirect:
  688.         begin
  689.           if FData is TRxQuery then TRxQuery(FData).ExecDirect
  690.           else ModeError;
  691.         end;
  692.       rqOpenOrExec:
  693.         begin
  694.           if FData is TRxQuery then TRxQuery(FData).OpenOrExec(True)
  695.           else FData.Open;
  696.         end;
  697.     end;
  698.   except
  699.     HandleException;
  700.   end;
  701. end;
  702. {$ENDIF WIN32}
  703. { TSQLScript }
  704. constructor TSQLScript.Create(AOwner: TComponent);
  705. begin
  706.   inherited Create(AOwner);
  707.   FSQL := TStringList.Create;
  708.   TStringList(SQL).OnChange := QueryChanged;
  709.   FParams := TParams.Create{$IFDEF RX_D4}(Self){$ENDIF};
  710.   FQuery := TRxQuery.Create(Self);
  711.   FSemicolonTerm := True;
  712.   FTerm := DefaultTermChar;
  713. end;
  714. destructor TSQLScript.Destroy;
  715. begin
  716.   FQuery.Free;
  717.   FSQL.Free;
  718.   FParams.Free;
  719.   inherited Destroy;
  720. end;
  721. function TSQLScript.GetDatabase: TDatabase;
  722. begin
  723.   Result := FQuery.Database;
  724. end;
  725. function TSQLScript.GetDatabaseName: string;
  726. begin
  727.   Result := FQuery.DatabaseName;
  728. end;
  729. procedure TSQLScript.SetDatabaseName(const Value: string);
  730. begin
  731.   FQuery.DatabaseName := Value;
  732. end;
  733. {$IFDEF WIN32}
  734. function TSQLScript.GetSessionName: string;
  735. begin
  736.   Result := FQuery.SessionName;
  737. end;
  738. procedure TSQLScript.SetSessionName(const Value: string);
  739. begin
  740.   FQuery.SessionName := Value;
  741. end;
  742. function TSQLScript.GetDBSession: TSession;
  743. begin
  744.   Result := FQuery.DBSession;
  745. end;
  746. {$ENDIF WIN32}
  747. procedure TSQLScript.CheckExecQuery(LineNo, StatementNo: Integer);
  748. var
  749.   Done: Boolean;
  750.   Action: TScriptAction;
  751.   I: Integer;
  752.   Param: TParam;
  753. {$IFNDEF WIN32}
  754.   Msg: array[0..255] of Char;
  755. {$ENDIF}
  756.   S: string;
  757. begin
  758.   Done := False;
  759.   repeat
  760.     try
  761.       if IgnoreParams then FQuery.ExecDirect
  762.       else begin
  763.         for I := 0 to FQuery.Params.Count - 1 do begin
  764.           Param := FQuery.Params[I];
  765.           Param.Assign(Params.ParamByName(Param.Name));
  766.         end;
  767.         FQuery.ExecSQL;
  768.       end;
  769.       Done := True;
  770.     except
  771.       on E: EDatabaseError do begin
  772.         Action := saFail;
  773.         S := Format(ResStr(SParseError), [ResStr(SMsgdlgError), LineNo]);
  774.         if E is EDBEngineError then
  775.           TDBError.Create(EDBEngineError(E), 0, LineNo,
  776.             {$IFDEF WIN32} PChar(S) {$ELSE} StrPCopy(Msg, S) {$ENDIF})
  777.         else begin
  778.           if E.Message <> '' then E.Message := E.Message + '. ';
  779.           E.Message := E.Message + S;
  780.         end;
  781.         if Assigned(FOnScriptError) then
  782.           FOnScriptError(Self, E, LineNo, StatementNo, Action);
  783.         if Action = saFail then raise;
  784.         if Action = saAbort then SysUtils.Abort;
  785.         if Action = saContinue then begin
  786.           Application.HandleException(Self);
  787.           Done := True;
  788.         end
  789.         else if Action = saIgnore then Done := True;
  790.       end;
  791.     end;
  792.   until Done;
  793. end;
  794. procedure TSQLScript.ExecuteScript(StatementNo: Integer);
  795. var
  796.   S, LastStr: string;
  797.   IsTrans, SQLFilled, StmtFound: Boolean;
  798.   I, P, CurrStatement: Integer;
  799. begin
  800.   IsTrans := FTransaction {$IFNDEF WIN32} and Database.IsSQLBased {$ENDIF}
  801.     and not TransActive(Database) and (StatementNo < 0);
  802.   LastStr := '';
  803.   try
  804.     if IsTrans then begin
  805. {$IFDEF WIN32}
  806.       if not Database.IsSQLBased then
  807.         Database.TransIsolation := tiDirtyRead;
  808. {$ENDIF}
  809.       Database.StartTransaction;
  810.     end;
  811.   except
  812.     IsTrans := False;
  813.   end;
  814.   try
  815.     I := 0;
  816.     CurrStatement := 0;
  817.     StmtFound := False;
  818.     while I < SQL.Count do begin
  819.       FQuery.SQL.BeginUpdate;
  820.       try
  821.         FQuery.SQL.Clear;
  822.         SQLFilled := False;
  823.         repeat
  824.           if LastStr <> '' then begin
  825.             FQuery.SQL.Add(LastStr);
  826.             LastStr := '';
  827.           end;
  828.           if I < SQL.Count then begin
  829.             S := Trim(SQL[I]);
  830.             Inc(I);
  831.             P := Pos(';', S);
  832.             if (P > 0) and FSemicolonTerm then begin
  833.               LastStr := Trim(Copy(S, P + 1, MaxInt));
  834.               S := Copy(S, 1, P - 1);
  835.               if S <> '' then FQuery.SQL.Add(S);
  836.               SQLFilled := True;
  837.             end
  838.             else begin
  839.               if (S = Term) then SQLFilled := True
  840.               else if S <> '' then FQuery.SQL.Add(S);
  841.             end;
  842.           end
  843.           else SQLFilled := True;
  844.         until SQLFilled;
  845.       finally
  846.         FQuery.SQL.EndUpdate;
  847.       end;
  848.       if FQuery.SQL.Count > 0 then begin
  849.         if (StatementNo < 0) or (StatementNo = CurrStatement) then begin
  850.           StmtFound := True;
  851.           CheckExecQuery(I - 1, CurrStatement);
  852.           if StatementNo = CurrStatement then Break;
  853.         end;
  854.         Inc(CurrStatement);
  855.       end;
  856.     end;
  857.     if not StmtFound then begin
  858. {$IFDEF RX_D3}
  859.       DatabaseError(Format(SListIndexError, [StatementNo]));
  860. {$ELSE}
  861.       DatabaseError(Format('%s: %d', [LoadStr(SListIndexError), StatementNo]));
  862. {$ENDIF RX_D3}
  863.     end;
  864.     if IsTrans then Database.Commit;
  865.   except
  866.     if IsTrans then Database.Rollback;
  867.     raise;
  868.   end;
  869. end;
  870. procedure TSQLScript.ExecStatement(StatementNo: Integer);
  871. begin
  872.   if FSQL.Count = 0 then _DBError(SEmptySQLStatement);
  873.   FQuery.SetDBFlag(dbfExecScript, True);
  874.   try
  875.     if not Database.Connected then _DBError(SDatabaseClosed);
  876.     if Assigned(FBeforeExec) then FBeforeExec(Self);
  877.     ExecuteScript(StatementNo);
  878.     if Assigned(FAfterExec) then FAfterExec(Self);
  879.   finally
  880.     FQuery.SetDBFlag(dbfExecScript, False);
  881.   end;
  882. end;
  883. procedure TSQLScript.ExecSQL;
  884. begin
  885.   ExecStatement(-1);
  886. end;
  887. procedure TSQLScript.CreateParams(List: TParams; const Value: PChar);
  888. begin
  889.   CreateQueryParams(List, Value, False, ':', []);
  890. end;
  891. procedure TSQLScript.SetQuery(Value: TStrings);
  892. begin
  893.   TStringList(SQL).OnChange := nil;
  894.   FSQL.Assign(Value);
  895.   TStringList(SQL).OnChange := QueryChanged;
  896.   QueryChanged(nil);
  897. end;
  898. function TSQLScript.GetText: {$IFDEF WIN32} string {$ELSE} PChar {$ENDIF};
  899. begin
  900. {$IFDEF WIN32}
  901.   Result := SQL.Text;
  902. {$ELSE}
  903.   Result := SQL.GetText;
  904. {$ENDIF}
  905. end;
  906. procedure TSQLScript.QueryChanged(Sender: TObject);
  907. var
  908.   List: TParams;
  909. {$IFNDEF WIN32}
  910.   P: PChar;
  911. {$ENDIF}
  912. begin
  913. {$IFDEF RX_D4}
  914.   if not (csReading in ComponentState) then begin
  915. {$ENDIF RX_D4}
  916.     List := TParams.Create{$IFDEF RX_D4}(Self){$ENDIF};
  917.     try
  918.   {$IFDEF WIN32}
  919.       CreateParams(List, PChar(Text));
  920.   {$ELSE}
  921.       P := GetText;
  922.       try
  923.         CreateParams(List, P);
  924.       finally
  925.         StrDispose(P);
  926.       end;
  927.   {$ENDIF WIN32}
  928.       List.AssignValues(FParams);
  929.   {$IFDEF RX_D4}
  930.       FParams.Clear;
  931.       FParams.Assign(List);
  932.     finally
  933.   {$ELSE}
  934.       FParams.Free;
  935.       FParams := List;
  936.     except
  937.   {$ENDIF RX_D4}
  938.       List.Free;
  939.     end;
  940. {$IFDEF RX_D4}
  941.   end
  942.   else begin
  943.     FParams.Clear;
  944.     CreateParams(FParams, PChar(Text));
  945.   end;
  946. {$ENDIF RX_D4}
  947. end;
  948. function TSQLScript.ParamByName(const Value: string): TParam;
  949. begin
  950.   Result := FParams.ParamByName(Value);
  951. end;
  952. procedure TSQLScript.SetParamsList(Value: TParams);
  953. begin
  954.   FParams.AssignValues(Value);
  955. end;
  956. function TSQLScript.GetParamsCount: Cardinal;
  957. begin
  958.   Result := FParams.Count;
  959. end;
  960. {$IFDEF RX_D4}
  961. procedure TSQLScript.DefineProperties(Filer: TFiler);
  962. begin
  963.   inherited DefineProperties(Filer);
  964.   Filer.DefineProperty('ParamData', ReadParamData, WriteParamData, True);
  965. end;
  966. procedure TSQLScript.ReadParamData(Reader: TReader);
  967. begin
  968.   Reader.ReadValue;
  969.   Reader.ReadCollection(FParams);
  970. end;
  971. procedure TSQLScript.WriteParamData(Writer: TWriter);
  972. begin
  973.   Writer.WriteCollection(Params);
  974. end;
  975. {$ENDIF RX_D4}
  976. end.