djjd47130

SQL Executer v3

Jul 19th, 2014
337
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 8.97 KB | None | 0 0
  1. unit SQLExec;
  2.  
  3. (*
  4.   Executes a large SQL script, splitting at GO statements
  5. *)
  6.  
  7. interface
  8.  
  9. uses
  10.   Windows, Classes, SysUtils, DB, ADODB,
  11.   Dialogs;
  12.  
  13. const
  14.   SE_ERR_NONE = 0;
  15.   SE_ERR_UNKNOWN = 1;
  16.   SE_ERR_CONNECTION_FAIL = 2;
  17.   SE_ERR_INVALID_CONNECTION = 3;
  18.   SE_ERR_PARSE = 4;
  19.   SE_ERR_EXECUTE = 5;
  20.  
  21. type
  22.   ESQLExecScriptException = class;
  23.   TSQLExecBlock = class;
  24.   TSQLExecBlocks = class;
  25.   TSQLExec = class;
  26.  
  27.  
  28.   ESQLExecScriptException = class(Exception)
  29.   private
  30.     FErrorCode: Integer;
  31.     FBlock: TSQLExecBlock;
  32.   public
  33.     constructor Create(const Msg: string; const ErrCode: Integer;
  34.       ABlock: TSQLExecBlock);
  35.     property ErrorCode: Integer read FErrorCode write FErrorCode;
  36.     property Block: TSQLExecBlock read FBlock;
  37.   end;
  38.  
  39.  
  40.   TSQLExecStatus = (sePending, seExecuting, seSuccess, seFail);
  41.   TSQLExecResult = (srSuccess, srConnFail, srSQLFail);
  42.  
  43.   TSQLExecOption = (soUseTransactions, soAbortOnFail, soForceParse);
  44.   TSQLExecOptions = set of TSQLExecOption;
  45.  
  46.   TSQLBlockEvent = procedure(Sender: TSQLExec; Block: TSQLExecBlock) of object;
  47.  
  48.   TSQLExecBlock = class(TObject)
  49.   private
  50.     FOwner: TSQLExecBlocks;
  51.     FSQL: TStringList;
  52.     FStatus: TSQLExecStatus;
  53.     FLine: Integer;
  54.     FMessage: String;
  55.     function GetSQL: TStrings;
  56.     procedure SetSQL(const Value: TStrings);
  57.     function GetIndex: Integer;
  58.   public
  59.     constructor Create(AOwner: TSQLExecBlocks);
  60.     destructor Destroy; override;
  61.     property Index: Integer read GetIndex;
  62.     property Status: TSQLExecStatus read FStatus;
  63.     property SQL: TStrings read GetSQL write SetSQL;
  64.     property Line: Integer read FLine;
  65.     property Message: String read FMessage;
  66.   end;
  67.  
  68.   TSQLExecBlocks = class(TObject)
  69.   private
  70.     FOwner: TSQLExec;
  71.     FItems: TList;
  72.     function GetItem(Index: Integer): TSQLExecBlock;
  73.   public
  74.     constructor Create(AOwner: TSQLExec);
  75.     destructor Destroy; override;
  76.     function Add: TSQLExecBlock;
  77.     procedure Delete(const Index: Integer);
  78.     function Count: Integer;
  79.     function IndexOf(ABlock: TSQLExecBlock): Integer;
  80.     procedure Clear;
  81.     property Items[Index: Integer]: TSQLExecBlock read GetItem; default;
  82.   end;
  83.  
  84.   TSQLExec = class(TComponent)
  85.   private
  86.     FSQL: TStringList;
  87.     FBlocks: TSQLExecBlocks;
  88.     FConnection: TADOConnection;
  89.     FOptions: TSQLExecOptions;
  90.     FParsed: Boolean;
  91.     FOnBlockStart: TSQLBlockEvent;
  92.     FOnBlockFinish: TSQLBlockEvent;
  93.     FSplitWord: String;
  94.     function GetSQL: TStrings;
  95.     procedure SetSQL(const Value: TStrings);
  96.     procedure SetConnection(const Value: TADOConnection);
  97.     procedure SQLChanged(Sender: TObject);
  98.     procedure Invalidate;
  99.     procedure SetSplitWord(const Value: String);
  100.   public
  101.     constructor Create(AOwner: TComponent); override;
  102.     destructor Destroy; override;
  103.     procedure ParseSQL;
  104.     function Execute: TSQLExecResult;
  105.     function LineCount: Integer;
  106.     function BlockCount: Integer;
  107.     property Parsed: Boolean read FParsed;
  108.     property Blocks: TSQLExecBlocks read FBlocks;
  109.   published
  110.     property SQL: TStrings read GetSQL write SetSQL;
  111.     property Connection: TADOConnection read FConnection write SetConnection;
  112.     property Options: TSQLExecOptions read FOptions write FOptions;
  113.     property SplitWord: String read FSplitWord write SetSplitWord;
  114.     property OnBlockStart: TSQLBlockEvent read FOnBlockStart write FOnBlockStart;
  115.     property OnBlockFinish: TSQLBlockEvent read FOnBlockFinish write FOnBlockFinish;
  116.   end;
  117.  
  118.  
  119. implementation
  120.  
  121. { ESQLExecScriptError }
  122.  
  123. constructor ESQLExecScriptException.Create(const Msg: string;
  124.   const ErrCode: Integer; ABlock: TSQLExecBlock);
  125. begin
  126.   inherited Create(Msg);
  127.   ErrorCode := ErrCode;
  128.   FBlock:= ABlock;
  129. end;
  130.  
  131. { TSQLExecBlock }
  132.  
  133. constructor TSQLExecBlock.Create(AOwner: TSQLExecBlocks);
  134. begin
  135.   FOwner:= AOwner;
  136.   FSQL:= TStringList.Create;
  137.   FStatus:= sePending;
  138.   FMessage:= '';
  139. end;
  140.  
  141. destructor TSQLExecBlock.Destroy;
  142. begin
  143.   FSQL.Free;
  144.   inherited;
  145. end;
  146.  
  147. function TSQLExecBlock.GetIndex: Integer;
  148. begin
  149.   Result:= FOwner.FItems.IndexOf(Self);
  150. end;
  151.  
  152. function TSQLExecBlock.GetSQL: TStrings;
  153. begin
  154.   Result:= TStrings(FSQL);
  155. end;
  156.  
  157. procedure TSQLExecBlock.SetSQL(const Value: TStrings);
  158. begin
  159.   FSQL.Assign(Value);
  160. end;
  161.  
  162. { TSQLExecBlocks }
  163.  
  164. constructor TSQLExecBlocks.Create(AOwner: TSQLExec);
  165. begin
  166.   FOwner:= AOwner;
  167.   FItems:= TList.Create;
  168. end;
  169.  
  170. destructor TSQLExecBlocks.Destroy;
  171. begin
  172.   Clear;
  173.   FItems.Free;
  174.   inherited;
  175. end;
  176.  
  177. function TSQLExecBlocks.Add: TSQLExecBlock;
  178. begin
  179.   Result:= TSQLExecBlock.Create(Self);
  180.   FItems.Add(Result);
  181. end;
  182.  
  183. procedure TSQLExecBlocks.Clear;
  184. begin
  185.   while Count > 0 do
  186.     Delete(0);
  187. end;
  188.  
  189. function TSQLExecBlocks.Count: Integer;
  190. begin
  191.   Result:= FItems.Count;
  192. end;
  193.  
  194. procedure TSQLExecBlocks.Delete(const Index: Integer);
  195. begin
  196.   TSQLExecBlock(FItems[Index]).Free;
  197.   FItems.Delete(Index);
  198. end;
  199.  
  200. function TSQLExecBlocks.GetItem(Index: Integer): TSQLExecBlock;
  201. begin
  202.   Result:= TSQLExecBlock(FItems[Index]);
  203. end;
  204.  
  205. function TSQLExecBlocks.IndexOf(ABlock: TSQLExecBlock): Integer;
  206. begin
  207.   Result:= FItems.IndexOf(ABlock);
  208. end;
  209.  
  210. { TSQLExec }
  211.  
  212. constructor TSQLExec.Create(AOwner: TComponent);
  213. begin
  214.   inherited;
  215.   FSQL:= TStringList.Create;
  216.   FSQL.OnChange:= SQLChanged;
  217.   FBlocks:= TSQLExecBlocks.Create(Self);
  218.   FConnection:= nil;
  219.   FOptions:= [soUseTransactions,soAbortOnFail];
  220.   FSplitWord:= 'go';
  221. end;
  222.  
  223. destructor TSQLExec.Destroy;
  224. begin
  225.   FBlocks.Free;
  226.   FSQL.Free;
  227.   inherited;
  228. end;
  229.  
  230. procedure TSQLExec.ParseSQL;
  231. var
  232.   X: Integer;
  233.   S: String;
  234.   B: TSQLExecBlock;
  235. begin
  236.   FBlocks.Clear;
  237.   B:= FBlocks.Add;        //Add first block
  238.   B.FLine:= 0;            //Assign the starting line # of block
  239.   try
  240.     for X := 0 to FSQL.Count - 1 do begin
  241.       S:= FSQL[X];          //Get copy of line to string
  242.       if Pos('use ', LowerCase(Trim(S))) = 1 then begin
  243.         //FSQL[X]:= '';       //Temporarily disabled
  244.       end else
  245.       if SameText(FSplitWord, Trim(S)) then begin
  246.         B:= FBlocks.Add;    //Add a new block
  247.         B.FLine:= X;        //Assign the starting line # of block
  248.       end else begin
  249.         B.SQL.Append(S);    //Add SQL script to current block
  250.       end;
  251.     end;
  252.     FParsed:= True;
  253.   except
  254.     on e: Exception do begin
  255.       raise ESQLExecScriptException.Create(e.Message, SE_ERR_PARSE, B);
  256.     end;
  257.   end;
  258. end;
  259.  
  260. function TSQLExec.Execute: TSQLExecResult;
  261. var
  262.   B: TSQLExecBlock;
  263.   X: Integer;
  264.   R: Integer;
  265.   EM: String;
  266. begin
  267.   Result:= srSuccess;
  268.   if (soForceParse in FOptions) or (not FParsed) then
  269.     ParseSQL;
  270.   //Begin transaction if configured
  271.   if soUseTransactions in FOptions then
  272.     FConnection.BeginTrans;
  273.   try
  274.     if not FConnection.Connected then begin
  275.       try
  276.         FConnection.Connected:= True;
  277.       except
  278.         on e: Exception do begin
  279.           Result:= srConnFail;
  280.           EM:= 'Error connecting to database: '+e.Message;
  281.           raise ESQLExecScriptException.Create(EM, SE_ERR_CONNECTION_FAIL, nil);
  282.         end;
  283.       end;
  284.     end;
  285.     for X := 0 to FBlocks.Count-1 do begin
  286.       B:= FBlocks[X];
  287.       B.FStatus:= seExecuting;
  288.       if Assigned(FOnBlockStart) then
  289.         FOnBlockStart(Self, B);
  290.       try
  291.         if Trim(B.SQL.Text) <> '' then begin
  292.           FConnection.Execute(B.SQL.Text);
  293.         end;
  294.         B.FStatus:= seSuccess;
  295.       except
  296.         on e: Exception do begin
  297.           B.FStatus:= seFail;
  298.           Result:= srSQLFail;
  299.           if soAbortOnFail in FOptions then begin
  300.             EM:= 'Error on Line '+IntToStr(B.Line)+': '+e.Message;
  301.             raise ESQLExecScriptException.Create(EM, SE_ERR_EXECUTE, B);
  302.           end;
  303.         end;
  304.       end;
  305.       if Assigned(FOnBlockFinish) then
  306.         FOnBlockFinish(Self, B);
  307.     end; //of for loop
  308.     //Commit transaction if configured
  309.     if soUseTransactions in FOptions then
  310.       FConnection.CommitTrans;
  311.     //Everything succeeded
  312.     Result:= srSuccess;
  313.   except
  314.     on e: Exception do begin
  315.       Result:= srSQLFail;
  316.       //Rollback transaction if configured
  317.       if soUseTransactions in FOptions then
  318.         if soAbortOnFail in FOptions then
  319.           FConnection.RollbackTrans;
  320.       raise e; //Re-raise exception
  321.     end;
  322.   end;
  323. end;
  324.  
  325. procedure TSQLExec.Invalidate;
  326. begin
  327.   FParsed:= False;
  328.   FBlocks.Clear;
  329. end;
  330.  
  331. function TSQLExec.LineCount: Integer;
  332. begin
  333.   Result:= FSQL.Count;
  334. end;
  335.  
  336. function TSQLExec.BlockCount: Integer;
  337. begin
  338.   if not FParsed then
  339.     ParseSQL;
  340.   Result:= FBlocks.Count;
  341. end;
  342.  
  343. function TSQLExec.GetSQL: TStrings;
  344. begin
  345.   Result:= TStrings(FSQL);
  346. end;
  347.  
  348. procedure TSQLExec.SetConnection(const Value: TADOConnection);
  349. begin
  350.   FConnection := Value;
  351. end;
  352.  
  353. procedure TSQLExec.SetSplitWord(const Value: String);
  354. begin
  355.   FSplitWord := Value;
  356.   Invalidate;
  357. end;
  358.  
  359. procedure TSQLExec.SetSQL(const Value: TStrings);
  360. begin
  361.   FSQL.Assign(Value);
  362.   Invalidate;
  363. end;
  364.  
  365. procedure TSQLExec.SQLChanged(Sender: TObject);
  366. begin
  367.   Invalidate;
  368. end;
  369.  
  370. end.
Advertisement
Add Comment
Please, Sign In to add comment