sqldb.pp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393
  1. {
  2. Copyright (c) 2004 by Joost van der Sluis
  3. SQL database & dataset
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. unit sqldb;
  11. {$mode objfpc}
  12. {$H+}
  13. {$M+} // ### remove this!!!
  14. interface
  15. uses SysUtils, Classes, DB;
  16. type TSchemaType = (stNoSchema, stTables, stSysTables, stProcedures, stColumns, stProcedureParams, stIndexes, stPackages);
  17. TConnOption = (sqSupportParams);
  18. TConnOptions= set of TConnOption;
  19. type
  20. TSQLConnection = class;
  21. TSQLTransaction = class;
  22. TSQLQuery = class;
  23. TSQLScript = class;
  24. TStatementType = (stNone, stSelect, stInsert, stUpdate, stDelete,
  25. stDDL, stGetSegment, stPutSegment, stExecProcedure,
  26. stStartTrans, stCommit, stRollback, stSelectForUpd);
  27. TSQLHandle = Class(TObject)
  28. end;
  29. { TSQLCursor }
  30. TSQLCursor = Class(TSQLHandle)
  31. public
  32. FPrepared : Boolean;
  33. FInitFieldDef : Boolean;
  34. FStatementType : TStatementType;
  35. FBlobStrings : TStringList; // list of strings in which the blob-fields are stored
  36. public
  37. constructor Create;
  38. destructor Destroy; override;
  39. end;
  40. const
  41. StatementTokens : Array[TStatementType] of string = ('(none)', 'select',
  42. 'insert', 'update', 'delete',
  43. 'create', 'get', 'put', 'execute',
  44. 'start','commit','rollback', '?'
  45. );
  46. { TSQLConnection }
  47. type
  48. { TSQLConnection }
  49. TSQLConnection = class (TDatabase)
  50. private
  51. FPassword : string;
  52. FTransaction : TSQLTransaction;
  53. FUserName : string;
  54. FHostName : string;
  55. FCharSet : string;
  56. FRole : String;
  57. procedure SetTransaction(Value : TSQLTransaction);
  58. procedure GetDBInfo(const SchemaType : TSchemaType; const SchemaObjectName, ReturnField : string; List: TStrings);
  59. protected
  60. FConnOptions : TConnOptions;
  61. function StrToStatementType(s : string) : TStatementType; virtual;
  62. procedure DoInternalConnect; override;
  63. procedure DoInternalDisconnect; override;
  64. function GetAsSQLText(Field : TField) : string; overload; virtual;
  65. function GetAsSQLText(Param : TParam) : string; overload; virtual;
  66. function GetHandle : pointer; virtual; virtual;
  67. Function AllocateCursorHandle : TSQLCursor; virtual; abstract;
  68. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); virtual; abstract;
  69. Function AllocateTransactionHandle : TSQLHandle; virtual; abstract;
  70. procedure PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams); virtual; abstract;
  71. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); virtual; abstract;
  72. function Fetch(cursor : TSQLCursor) : boolean; virtual; abstract;
  73. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); virtual; abstract;
  74. procedure UnPrepareStatement(cursor : TSQLCursor); virtual; abstract;
  75. procedure FreeFldBuffers(cursor : TSQLCursor); virtual;
  76. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer) : boolean; virtual; abstract;
  77. function GetTransactionHandle(trans : TSQLHandle): pointer; virtual; abstract;
  78. function Commit(trans : TSQLHandle) : boolean; virtual; abstract;
  79. function RollBack(trans : TSQLHandle) : boolean; virtual; abstract;
  80. function StartdbTransaction(trans : TSQLHandle; aParams : string) : boolean; virtual; abstract;
  81. procedure CommitRetaining(trans : TSQLHandle); virtual; abstract;
  82. procedure RollBackRetaining(trans : TSQLHandle); virtual; abstract;
  83. procedure UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string); virtual;
  84. function GetSchemaInfoSQL(SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string; virtual;
  85. procedure LoadBlobIntoStream(Field: TField;AStream: TMemoryStream;cursor: TSQLCursor;ATransaction : TSQLTransaction); virtual;
  86. public
  87. property Handle: Pointer read GetHandle;
  88. destructor Destroy; override;
  89. procedure StartTransaction; override;
  90. procedure EndTransaction; override;
  91. property ConnOptions: TConnOptions read FConnOptions;
  92. procedure ExecuteDirect(SQL : String); overload; virtual;
  93. procedure ExecuteDirect(SQL : String; ATransaction : TSQLTransaction); overload; virtual;
  94. procedure GetTableNames(List : TStrings; SystemTables : Boolean = false); virtual;
  95. procedure GetProcedureNames(List : TStrings); virtual;
  96. procedure GetFieldNames(const TableName : string; List : TStrings); virtual;
  97. published
  98. property Password : string read FPassword write FPassword;
  99. property Transaction : TSQLTransaction read FTransaction write SetTransaction;
  100. property UserName : string read FUserName write FUserName;
  101. property CharSet : string read FCharSet write FCharSet;
  102. property HostName : string Read FHostName Write FHostName;
  103. property Connected;
  104. Property Role : String read FRole write FRole;
  105. property DatabaseName;
  106. property KeepConnection;
  107. property LoginPrompt;
  108. property Params;
  109. property OnLogin;
  110. end;
  111. { TSQLTransaction }
  112. TCommitRollbackAction = (caNone, caCommit, caCommitRetaining, caRollback,
  113. caRollbackRetaining);
  114. TSQLTransaction = class (TDBTransaction)
  115. private
  116. FTrans : TSQLHandle;
  117. FAction : TCommitRollbackAction;
  118. FParams : TStringList;
  119. protected
  120. function GetHandle : Pointer; virtual;
  121. Procedure SetDatabase (Value : TDatabase); override;
  122. public
  123. procedure Commit; virtual;
  124. procedure CommitRetaining; virtual;
  125. procedure Rollback; virtual;
  126. procedure RollbackRetaining; virtual;
  127. procedure StartTransaction; override;
  128. constructor Create(AOwner : TComponent); override;
  129. destructor Destroy; override;
  130. property Handle: Pointer read GetHandle;
  131. procedure EndTransaction; override;
  132. published
  133. property Action : TCommitRollbackAction read FAction write FAction;
  134. property Database;
  135. property Params : TStringList read FParams write FParams;
  136. end;
  137. { TSQLQuery }
  138. TSQLQuery = class (Tbufdataset)
  139. private
  140. FCursor : TSQLCursor;
  141. FUpdateable : boolean;
  142. FTableName : string;
  143. FSQL : TStringList;
  144. FUpdateSQL,
  145. FInsertSQL,
  146. FDeleteSQL : TStringList;
  147. FIsEOF : boolean;
  148. FLoadingFieldDefs : boolean;
  149. FIndexDefs : TIndexDefs;
  150. FReadOnly : boolean;
  151. FUpdateMode : TUpdateMode;
  152. FParams : TParams;
  153. FusePrimaryKeyAsKey : Boolean;
  154. FSQLBuf : String;
  155. FFromPart : String;
  156. FWhereStartPos : integer;
  157. FWhereStopPos : integer;
  158. FParseSQL : boolean;
  159. FMasterLink : TMasterParamsDatalink;
  160. // FSchemaInfo : TSchemaInfo;
  161. FUpdateQry,
  162. FDeleteQry,
  163. FInsertQry : TSQLQuery;
  164. procedure FreeFldBuffers;
  165. procedure InitUpdates(ASQL : string);
  166. function GetIndexDefs : TIndexDefs;
  167. function GetStatementType : TStatementType;
  168. procedure SetIndexDefs(AValue : TIndexDefs);
  169. procedure SetReadOnly(AValue : Boolean);
  170. procedure SetParseSQL(AValue : Boolean);
  171. procedure SetUsePrimaryKeyAsKey(AValue : Boolean);
  172. procedure SetUpdateMode(AValue : TUpdateMode);
  173. procedure OnChangeSQL(Sender : TObject);
  174. procedure OnChangeModifySQL(Sender : TObject);
  175. procedure Execute;
  176. Procedure SQLParser(var ASQL : string);
  177. procedure ApplyFilter;
  178. Function AddFilter(SQLstr : string) : string;
  179. protected
  180. // abstract & virtual methods of TBufDataset
  181. function Fetch : boolean; override;
  182. function LoadField(FieldDef : TFieldDef;buffer : pointer) : boolean; override;
  183. // abstract & virtual methods of TDataset
  184. procedure UpdateIndexDefs; override;
  185. procedure SetDatabase(Value : TDatabase); override;
  186. Procedure SetTransaction(Value : TDBTransaction); override;
  187. procedure InternalAddRecord(Buffer: Pointer; AAppend: Boolean); override;
  188. procedure InternalClose; override;
  189. procedure InternalInitFieldDefs; override;
  190. procedure InternalOpen; override;
  191. function GetCanModify: Boolean; override;
  192. procedure ApplyRecUpdate(UpdateKind : TUpdateKind); override;
  193. Function IsPrepared : Boolean; virtual;
  194. Procedure SetActive (Value : Boolean); override;
  195. procedure SetFiltered(Value: Boolean); override;
  196. procedure SetFilterText(const Value: string); override;
  197. Function GetDataSource : TDatasource; override;
  198. Procedure SetDataSource(AValue : TDatasource);
  199. procedure LoadBlobIntoStream(Field: TField;AStream: TMemoryStream); override;
  200. public
  201. procedure Prepare; virtual;
  202. procedure UnPrepare; virtual;
  203. procedure ExecSQL; virtual;
  204. constructor Create(AOwner : TComponent); override;
  205. destructor Destroy; override;
  206. procedure SetSchemaInfo( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string); virtual;
  207. property Prepared : boolean read IsPrepared;
  208. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  209. published
  210. // redeclared data set properties
  211. property Active;
  212. property Filter;
  213. property Filtered;
  214. // property FilterOptions;
  215. property BeforeOpen;
  216. property AfterOpen;
  217. property BeforeClose;
  218. property AfterClose;
  219. property BeforeInsert;
  220. property AfterInsert;
  221. property BeforeEdit;
  222. property AfterEdit;
  223. property BeforePost;
  224. property AfterPost;
  225. property BeforeCancel;
  226. property AfterCancel;
  227. property BeforeDelete;
  228. property AfterDelete;
  229. property BeforeScroll;
  230. property AfterScroll;
  231. property OnCalcFields;
  232. property OnDeleteError;
  233. property OnEditError;
  234. property OnFilterRecord;
  235. property OnNewRecord;
  236. property OnPostError;
  237. property AutoCalcFields;
  238. property Database;
  239. property Transaction;
  240. property ReadOnly : Boolean read FReadOnly write SetReadOnly;
  241. property SQL : TStringlist read FSQL write FSQL;
  242. property UpdateSQL : TStringlist read FUpdateSQL write FUpdateSQL;
  243. property InsertSQL : TStringlist read FInsertSQL write FInsertSQL;
  244. property DeleteSQL : TStringlist read FDeleteSQL write FDeleteSQL;
  245. property IndexDefs : TIndexDefs read GetIndexDefs;
  246. property Params : TParams read FParams write FParams;
  247. property UpdateMode : TUpdateMode read FUpdateMode write SetUpdateMode;
  248. property UsePrimaryKeyAsKey : boolean read FUsePrimaryKeyAsKey write SetUsePrimaryKeyAsKey;
  249. property StatementType : TStatementType read GetStatementType;
  250. property ParseSQL : Boolean read FParseSQL write SetParseSQL;
  251. Property DataSource : TDatasource Read GetDataSource Write SetDatasource;
  252. // property SchemaInfo : TSchemaInfo read FSchemaInfo default stNoSchema;
  253. end;
  254. { TSQLScript }
  255. TSQLScript = class (Tcomponent)
  256. private
  257. FScript : TStrings;
  258. FQuery : TSQLQuery;
  259. FDatabase : TDatabase;
  260. FTransaction : TDBTransaction;
  261. protected
  262. procedure SetScript(const AValue: TStrings);
  263. Procedure SetDatabase (Value : TDatabase); virtual;
  264. Procedure SetTransaction(Value : TDBTransaction); virtual;
  265. Procedure CheckDatabase;
  266. public
  267. constructor Create(AOwner : TComponent); override;
  268. destructor Destroy; override;
  269. procedure ExecuteScript;
  270. Property Script : TStrings Read FScript Write SetScript;
  271. Property DataBase : TDatabase Read FDatabase Write SetDatabase;
  272. Property Transaction : TDBTransaction Read FTransaction Write SetTransaction;
  273. end;
  274. implementation
  275. uses dbconst, strutils;
  276. { TSQLConnection }
  277. function TSQLConnection.StrToStatementType(s : string) : TStatementType;
  278. var T : TStatementType;
  279. begin
  280. S:=Lowercase(s);
  281. For t:=stselect to strollback do
  282. if (S=StatementTokens[t]) then
  283. Exit(t);
  284. end;
  285. procedure TSQLConnection.SetTransaction(Value : TSQLTransaction);
  286. begin
  287. if FTransaction<>value then
  288. begin
  289. if Assigned(FTransaction) and FTransaction.Active then
  290. DatabaseError(SErrAssTransaction);
  291. if Assigned(Value) then
  292. Value.Database := Self;
  293. FTransaction := Value;
  294. end;
  295. end;
  296. procedure TSQLConnection.UpdateIndexDefs(var IndexDefs : TIndexDefs;TableName : string);
  297. begin
  298. // Empty abstract
  299. end;
  300. procedure TSQLConnection.DoInternalConnect;
  301. begin
  302. if (DatabaseName = '') then
  303. DatabaseError(SErrNoDatabaseName,self);
  304. end;
  305. procedure TSQLConnection.DoInternalDisconnect;
  306. begin
  307. end;
  308. destructor TSQLConnection.Destroy;
  309. begin
  310. inherited Destroy;
  311. end;
  312. procedure TSQLConnection.StartTransaction;
  313. begin
  314. if not assigned(Transaction) then
  315. DatabaseError(SErrConnTransactionnSet)
  316. else
  317. Transaction.StartTransaction;
  318. end;
  319. procedure TSQLConnection.EndTransaction;
  320. begin
  321. if not assigned(Transaction) then
  322. DatabaseError(SErrConnTransactionnSet)
  323. else
  324. Transaction.EndTransaction;
  325. end;
  326. Procedure TSQLConnection.ExecuteDirect(SQL: String);
  327. begin
  328. ExecuteDirect(SQL,FTransaction);
  329. end;
  330. Procedure TSQLConnection.ExecuteDirect(SQL: String; ATransaction : TSQLTransaction);
  331. var Cursor : TSQLCursor;
  332. begin
  333. if not assigned(ATransaction) then
  334. DatabaseError(SErrTransactionnSet);
  335. if not Connected then Open;
  336. if not ATransaction.Active then ATransaction.StartTransaction;
  337. try
  338. Cursor := AllocateCursorHandle;
  339. SQL := TrimRight(SQL);
  340. if SQL = '' then
  341. DatabaseError(SErrNoStatement);
  342. Cursor.FStatementType := stNone;
  343. PrepareStatement(cursor,ATransaction,SQL,Nil);
  344. execute(cursor,ATransaction, Nil);
  345. UnPrepareStatement(Cursor);
  346. finally;
  347. DeAllocateCursorHandle(Cursor);
  348. end;
  349. end;
  350. procedure TSQLConnection.GetDBInfo(const SchemaType : TSchemaType; const SchemaObjectName, ReturnField : string; List: TStrings);
  351. var qry : TSQLQuery;
  352. begin
  353. if not assigned(Transaction) then
  354. DatabaseError(SErrConnTransactionnSet);
  355. qry := tsqlquery.Create(nil);
  356. qry.transaction := Transaction;
  357. qry.database := Self;
  358. with qry do
  359. begin
  360. ParseSQL := False;
  361. SetSchemaInfo(SchemaType,SchemaObjectName,'');
  362. open;
  363. List.Clear;
  364. while not eof do
  365. begin
  366. List.Append(fieldbyname(ReturnField).asstring);
  367. Next;
  368. end;
  369. end;
  370. qry.free;
  371. end;
  372. procedure TSQLConnection.GetTableNames(List: TStrings; SystemTables: Boolean);
  373. begin
  374. if not systemtables then GetDBInfo(stTables,'','table_name',List)
  375. else GetDBInfo(stSysTables,'','table_name',List);
  376. end;
  377. procedure TSQLConnection.GetProcedureNames(List: TStrings);
  378. begin
  379. GetDBInfo(stProcedures,'','proc_name',List);
  380. end;
  381. procedure TSQLConnection.GetFieldNames(const TableName: string; List: TStrings);
  382. begin
  383. GetDBInfo(stColumns,TableName,'column_name',List);
  384. end;
  385. function TSQLConnection.GetAsSQLText(Field : TField) : string;
  386. begin
  387. if (not assigned(field)) or field.IsNull then Result := 'Null'
  388. else case field.DataType of
  389. ftString : Result := '''' + field.asstring + '''';
  390. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Field.AsDateTime) + '''';
  391. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:mm:ss',Field.AsDateTime) + ''''
  392. else
  393. Result := field.asstring;
  394. end; {case}
  395. end;
  396. function TSQLConnection.GetAsSQLText(Param: TParam) : string;
  397. begin
  398. if (not assigned(param)) or param.IsNull then Result := 'Null'
  399. else case param.DataType of
  400. ftString : Result := '''' + param.asstring + '''';
  401. ftDate : Result := '''' + FormatDateTime('yyyy-mm-dd',Param.AsDateTime) + '''';
  402. ftDateTime : Result := '''' + FormatDateTime('yyyy-mm-dd hh:mm:ss',Param.AsDateTime) + ''''
  403. else
  404. Result := Param.asstring;
  405. end; {case}
  406. end;
  407. function TSQLConnection.GetHandle: pointer;
  408. begin
  409. Result := nil;
  410. end;
  411. procedure TSQLConnection.FreeFldBuffers(cursor: TSQLCursor);
  412. begin
  413. cursor.FBlobStrings.Clear;
  414. end;
  415. function TSQLConnection.GetSchemaInfoSQL( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string) : string;
  416. begin
  417. DatabaseError(SMetadataUnavailable);
  418. end;
  419. procedure TSQLConnection.LoadBlobIntoStream(Field: TField;AStream: TMemoryStream; cursor: TSQLCursor;ATransaction : TSQLTransaction);
  420. var blobId : pinteger;
  421. BlobBuf : TBufBlobField;
  422. s : string;
  423. begin
  424. if not field.getData(@BlobBuf) then
  425. exit;
  426. blobId := @BlobBuf.BufBlobId;
  427. s := cursor.FBlobStrings.Strings[blobid^];
  428. AStream.WriteBuffer(s[1],length(s));
  429. AStream.seek(0,soFromBeginning);
  430. end;
  431. { TSQLTransaction }
  432. procedure TSQLTransaction.EndTransaction;
  433. begin
  434. rollback;
  435. end;
  436. function TSQLTransaction.GetHandle: pointer;
  437. begin
  438. Result := (Database as tsqlconnection).GetTransactionHandle(FTrans);
  439. end;
  440. procedure TSQLTransaction.Commit;
  441. begin
  442. if active then
  443. begin
  444. closedatasets;
  445. if (Database as tsqlconnection).commit(FTrans) then
  446. begin
  447. closeTrans;
  448. FreeAndNil(FTrans);
  449. end;
  450. end;
  451. end;
  452. procedure TSQLTransaction.CommitRetaining;
  453. begin
  454. if active then
  455. (Database as tsqlconnection).commitRetaining(FTrans);
  456. end;
  457. procedure TSQLTransaction.Rollback;
  458. begin
  459. if active then
  460. begin
  461. closedatasets;
  462. if (Database as tsqlconnection).RollBack(FTrans) then
  463. begin
  464. CloseTrans;
  465. FreeAndNil(FTrans);
  466. end;
  467. end;
  468. end;
  469. procedure TSQLTransaction.RollbackRetaining;
  470. begin
  471. if active then
  472. (Database as tsqlconnection).RollBackRetaining(FTrans);
  473. end;
  474. procedure TSQLTransaction.StartTransaction;
  475. var db : TSQLConnection;
  476. begin
  477. if Active then
  478. DatabaseError(SErrTransAlreadyActive);
  479. db := (Database as tsqlconnection);
  480. if Db = nil then
  481. DatabaseError(SErrDatabasenAssigned);
  482. if not Db.Connected then
  483. Db.Open;
  484. if not assigned(FTrans) then FTrans := Db.AllocateTransactionHandle;
  485. if Db.StartdbTransaction(FTrans,FParams.CommaText) then OpenTrans;
  486. end;
  487. constructor TSQLTransaction.Create(AOwner : TComponent);
  488. begin
  489. inherited Create(AOwner);
  490. FParams := TStringList.Create;
  491. end;
  492. destructor TSQLTransaction.Destroy;
  493. begin
  494. Rollback;
  495. FreeAndNil(FParams);
  496. inherited Destroy;
  497. end;
  498. Procedure TSQLTransaction.SetDatabase(Value : TDatabase);
  499. begin
  500. If Value<>Database then
  501. begin
  502. CheckInactive;
  503. If Assigned(Database) then
  504. with Database as TSqlConnection do
  505. if Transaction = self then Transaction := nil;
  506. inherited SetDatabase(Value);
  507. end;
  508. end;
  509. { TSQLQuery }
  510. procedure TSQLQuery.OnChangeSQL(Sender : TObject);
  511. begin
  512. UnPrepare;
  513. if (FSQL <> nil) then
  514. begin
  515. FParams.ParseSQL(FSQL.Text,True);
  516. If Assigned(FMasterLink) then
  517. FMasterLink.RefreshParamNames;
  518. end;
  519. end;
  520. procedure TSQLQuery.OnChangeModifySQL(Sender : TObject);
  521. begin
  522. CheckInactive;
  523. end;
  524. Procedure TSQLQuery.SetTransaction(Value : TDBTransaction);
  525. begin
  526. UnPrepare;
  527. inherited;
  528. end;
  529. procedure TSQLQuery.SetDatabase(Value : TDatabase);
  530. var db : tsqlconnection;
  531. begin
  532. if (Database <> Value) then
  533. begin
  534. UnPrepare;
  535. if assigned(FCursor) then (Database as TSQLConnection).DeAllocateCursorHandle(FCursor);
  536. db := value as tsqlconnection;
  537. inherited setdatabase(value);
  538. if assigned(value) and (Transaction = nil) and (Assigned(db.Transaction)) then
  539. transaction := Db.Transaction;
  540. end;
  541. end;
  542. Function TSQLQuery.IsPrepared : Boolean;
  543. begin
  544. Result := Assigned(FCursor) and FCursor.FPrepared;
  545. end;
  546. Function TSQLQuery.AddFilter(SQLstr : string) : string;
  547. begin
  548. if FWhereStartPos = 0 then
  549. SQLstr := SQLstr + ' where (' + Filter + ')'
  550. else if FWhereStopPos > 0 then
  551. system.insert(' and ('+Filter+') ',SQLstr,FWhereStopPos+1)
  552. else
  553. system.insert(' where ('+Filter+') ',SQLstr,FWhereStartPos);
  554. Result := SQLstr;
  555. end;
  556. procedure TSQLQuery.ApplyFilter;
  557. var S : String;
  558. begin
  559. FreeFldBuffers;
  560. (Database as tsqlconnection).UnPrepareStatement(FCursor);
  561. FIsEOF := False;
  562. inherited internalclose;
  563. s := FSQLBuf;
  564. if Filtered then s := AddFilter(s);
  565. (Database as tsqlconnection).PrepareStatement(Fcursor,(transaction as tsqltransaction),S,FParams);
  566. Execute;
  567. inherited InternalOpen;
  568. First;
  569. end;
  570. Procedure TSQLQuery.SetActive (Value : Boolean);
  571. begin
  572. inherited SetActive(Value);
  573. // The query is UnPrepared, so that if a transaction closes all datasets
  574. // they also get unprepared
  575. if not Value and IsPrepared then UnPrepare;
  576. end;
  577. procedure TSQLQuery.SetFiltered(Value: Boolean);
  578. begin
  579. if Value and not FParseSQL then DatabaseErrorFmt(SNoParseSQL,['Filtering ']);
  580. if (Filtered <> Value) then
  581. begin
  582. inherited setfiltered(Value);
  583. if active then ApplyFilter;
  584. end;
  585. end;
  586. procedure TSQLQuery.SetFilterText(const Value: string);
  587. begin
  588. if Value <> Filter then
  589. begin
  590. inherited SetFilterText(Value);
  591. if active then ApplyFilter;
  592. end;
  593. end;
  594. procedure TSQLQuery.Prepare;
  595. var
  596. db : tsqlconnection;
  597. sqltr : tsqltransaction;
  598. begin
  599. if not IsPrepared then
  600. begin
  601. db := (Database as tsqlconnection);
  602. sqltr := (transaction as tsqltransaction);
  603. if not assigned(Db) then
  604. DatabaseError(SErrDatabasenAssigned);
  605. if not assigned(sqltr) then
  606. DatabaseError(SErrTransactionnSet);
  607. if not Db.Connected then db.Open;
  608. if not sqltr.Active then sqltr.StartTransaction;
  609. // if assigned(fcursor) then FreeAndNil(fcursor);
  610. if not assigned(fcursor) then
  611. FCursor := Db.AllocateCursorHandle;
  612. FSQLBuf := TrimRight(FSQL.Text);
  613. if FSQLBuf = '' then
  614. DatabaseError(SErrNoStatement);
  615. SQLParser(FSQLBuf);
  616. if filtered then
  617. Db.PrepareStatement(Fcursor,sqltr,AddFilter(FSQLBuf),FParams)
  618. else
  619. Db.PrepareStatement(Fcursor,sqltr,FSQLBuf,FParams);
  620. if (FCursor.FStatementType = stSelect) then
  621. begin
  622. FCursor.FInitFieldDef := True;
  623. if not ReadOnly then InitUpdates(FSQLBuf);
  624. end;
  625. end;
  626. end;
  627. procedure TSQLQuery.UnPrepare;
  628. begin
  629. CheckInactive;
  630. if IsPrepared then with Database as TSQLConnection do
  631. UnPrepareStatement(FCursor);
  632. end;
  633. procedure TSQLQuery.FreeFldBuffers;
  634. begin
  635. if assigned(FCursor) then (Database as tsqlconnection).FreeFldBuffers(FCursor);
  636. end;
  637. function TSQLQuery.Fetch : boolean;
  638. begin
  639. if not (Fcursor.FStatementType in [stSelect]) then
  640. Exit;
  641. if not FIsEof then FIsEOF := not (Database as tsqlconnection).Fetch(Fcursor);
  642. Result := not FIsEOF;
  643. end;
  644. procedure TSQLQuery.Execute;
  645. begin
  646. If (FParams.Count>0) and Assigned(FMasterLink) then
  647. FMasterLink.CopyParamsFromMaster(False);
  648. (Database as tsqlconnection).execute(Fcursor,Transaction as tsqltransaction, FParams);
  649. end;
  650. function TSQLQuery.LoadField(FieldDef : TFieldDef;buffer : pointer) : boolean;
  651. begin
  652. result := (Database as tSQLConnection).LoadField(FCursor,FieldDef,buffer)
  653. end;
  654. procedure TSQLQuery.InternalAddRecord(Buffer: Pointer; AAppend: Boolean);
  655. begin
  656. // not implemented - sql dataset
  657. end;
  658. procedure TSQLQuery.InternalClose;
  659. begin
  660. if StatementType = stSelect then FreeFldBuffers;
  661. // Database and FCursor could be nil, for example if the database is not assigned, and .open is called
  662. if (not IsPrepared) and (assigned(database)) and (assigned(FCursor)) then (database as TSQLconnection).UnPrepareStatement(FCursor);
  663. if DefaultFields then
  664. DestroyFields;
  665. FIsEOF := False;
  666. if assigned(FUpdateQry) then FreeAndNil(FUpdateQry);
  667. if assigned(FInsertQry) then FreeAndNil(FInsertQry);
  668. if assigned(FDeleteQry) then FreeAndNil(FDeleteQry);
  669. // FRecordSize := 0;
  670. inherited internalclose;
  671. end;
  672. procedure TSQLQuery.InternalInitFieldDefs;
  673. begin
  674. if FLoadingFieldDefs then
  675. Exit;
  676. FLoadingFieldDefs := True;
  677. try
  678. FieldDefs.Clear;
  679. (Database as tsqlconnection).AddFieldDefs(fcursor,FieldDefs);
  680. finally
  681. FLoadingFieldDefs := False;
  682. end;
  683. end;
  684. procedure TSQLQuery.SQLParser(var ASQL : string);
  685. type TParsePart = (ppStart,ppSelect,ppWhere,ppFrom,ppOrder,ppComment,ppBogus);
  686. Var
  687. PSQL,CurrentP,
  688. PhraseP, PStatementPart : pchar;
  689. S : string;
  690. ParsePart : TParsePart;
  691. StrLength : Integer;
  692. begin
  693. PSQL:=Pchar(ASQL);
  694. ParsePart := ppStart;
  695. CurrentP := PSQL-1;
  696. PhraseP := PSQL;
  697. FWhereStartPos := 0;
  698. FWhereStopPos := 0;
  699. repeat
  700. begin
  701. inc(CurrentP);
  702. if CurrentP^ in [' ',#13,#10,#9,#0,'(',')',';'] then
  703. begin
  704. if (CurrentP-PhraseP > 0) or (CurrentP^ in [';',#0]) then
  705. begin
  706. strLength := CurrentP-PhraseP;
  707. Setlength(S,strLength);
  708. if strLength > 0 then Move(PhraseP^,S[1],(strLength));
  709. s := uppercase(s);
  710. case ParsePart of
  711. ppStart : begin
  712. FCursor.FStatementType := (Database as tsqlconnection).StrToStatementType(s);
  713. if FCursor.FStatementType = stSelect then ParsePart := ppSelect
  714. else break;
  715. if not FParseSQL then break;
  716. PStatementPart := CurrentP;
  717. end;
  718. ppSelect : begin
  719. if s = 'FROM' then
  720. begin
  721. ParsePart := ppFrom;
  722. PhraseP := CurrentP;
  723. PStatementPart := CurrentP;
  724. end;
  725. end;
  726. ppFrom : begin
  727. if (s = 'WHERE') or (s = 'ORDER') or (CurrentP^=#0) or (CurrentP^=';') then
  728. begin
  729. if (s = 'WHERE') then
  730. begin
  731. ParsePart := ppWhere;
  732. StrLength := PhraseP-PStatementPart;
  733. end
  734. else if (s = 'ORDER') then
  735. begin
  736. ParsePart := ppOrder;
  737. StrLength := PhraseP-PStatementPart
  738. end
  739. else
  740. begin
  741. ParsePart := ppBogus;
  742. StrLength := CurrentP-PStatementPart;
  743. end;
  744. Setlength(FFromPart,StrLength);
  745. Move(PStatementPart^,FFromPart[1],(StrLength));
  746. FFrompart := trim(FFrompart);
  747. FWhereStartPos := PStatementPart-PSQL+StrLength+1;
  748. PStatementPart := CurrentP;
  749. end;
  750. end;
  751. ppWhere : begin
  752. if (s = 'ORDER') or (CurrentP^=#0) or (CurrentP^=';') then
  753. begin
  754. ParsePart := ppBogus;
  755. FWhereStartPos := PStatementPart-PSQL;
  756. if s = 'ORDER' then
  757. FWhereStopPos := PhraseP-PSQL+1
  758. else
  759. FWhereStopPos := CurrentP-PSQL+1;
  760. end;
  761. end;
  762. end; {case}
  763. end;
  764. PhraseP := CurrentP+1;
  765. end
  766. end;
  767. until CurrentP^=#0;
  768. if (FWhereStartPos > 0) and (FWhereStopPos > 0) then
  769. begin
  770. system.insert('(',ASQL,FWhereStartPos+1);
  771. inc(FWhereStopPos);
  772. system.insert(')',ASQL,FWhereStopPos);
  773. end
  774. end;
  775. procedure TSQLQuery.InitUpdates(ASQL : string);
  776. begin
  777. if pos(',',FFromPart) > 0 then
  778. FUpdateable := False // select-statements from more then one table are not updateable
  779. else
  780. begin
  781. FUpdateable := True;
  782. FTableName := FFromPart;
  783. end;
  784. end;
  785. procedure TSQLQuery.InternalOpen;
  786. procedure InitialiseModifyQuery(var qry : TSQLQuery; aSQL: TSTringList);
  787. begin
  788. qry := TSQLQuery.Create(nil);
  789. with qry do
  790. begin
  791. ParseSQL := False;
  792. DataBase := Self.DataBase;
  793. Transaction := Self.Transaction;
  794. SQL.Assign(aSQL);
  795. end;
  796. end;
  797. var tel : integer;
  798. f : TField;
  799. s : string;
  800. begin
  801. try
  802. Prepare;
  803. if FCursor.FStatementType in [stSelect] then
  804. begin
  805. Execute;
  806. if FCursor.FInitFieldDef then InternalInitFieldDefs;
  807. if DefaultFields then
  808. begin
  809. CreateFields;
  810. if FUpdateable then
  811. begin
  812. if FusePrimaryKeyAsKey then
  813. begin
  814. UpdateIndexDefs;
  815. for tel := 0 to indexdefs.count-1 do {with indexdefs[tel] do}
  816. begin
  817. if ixPrimary in indexdefs[tel].options then
  818. begin
  819. // Todo: If there is more then one field in the key, that must be parsed
  820. s := indexdefs[tel].fields;
  821. F := Findfield(s);
  822. if F <> nil then
  823. F.ProviderFlags := F.ProviderFlags + [pfInKey];
  824. end;
  825. end;
  826. end;
  827. end;
  828. end;
  829. if FUpdateable then
  830. begin
  831. InitialiseModifyQuery(FDeleteQry,FDeleteSQL);
  832. InitialiseModifyQuery(FUpdateQry,FUpdateSQL);
  833. InitialiseModifyQuery(FInsertQry,FInsertSQL);
  834. end;
  835. end
  836. else
  837. DatabaseError(SErrNoSelectStatement,Self);
  838. except
  839. on E:Exception do
  840. raise;
  841. end;
  842. inherited InternalOpen;
  843. end;
  844. // public part
  845. procedure TSQLQuery.ExecSQL;
  846. begin
  847. try
  848. Prepare;
  849. Execute;
  850. finally
  851. // FCursor has to be assigned, or else the prepare went wrong before PrepareStatment was
  852. // called, so UnPrepareStatement shoudn't be called either
  853. if (not IsPrepared) and (assigned(database)) and (assigned(FCursor)) then (database as TSQLConnection).UnPrepareStatement(Fcursor);
  854. end;
  855. end;
  856. constructor TSQLQuery.Create(AOwner : TComponent);
  857. begin
  858. inherited Create(AOwner);
  859. FParams := TParams.create(self);
  860. FSQL := TStringList.Create;
  861. FSQL.OnChange := @OnChangeSQL;
  862. FUpdateSQL := TStringList.Create;
  863. FUpdateSQL.OnChange := @OnChangeModifySQL;
  864. FInsertSQL := TStringList.Create;
  865. FInsertSQL.OnChange := @OnChangeModifySQL;
  866. FDeleteSQL := TStringList.Create;
  867. FDeleteSQL.OnChange := @OnChangeModifySQL;
  868. FIndexDefs := TIndexDefs.Create(Self);
  869. FReadOnly := false;
  870. FParseSQL := True;
  871. // Delphi has upWhereAll as default, but since strings and oldvalue's don't work yet
  872. // (variants) set it to upWhereKeyOnly
  873. FUpdateMode := upWhereKeyOnly;
  874. FUsePrimaryKeyAsKey := True;
  875. end;
  876. destructor TSQLQuery.Destroy;
  877. begin
  878. if Active then Close;
  879. UnPrepare;
  880. if assigned(FCursor) then (Database as TSQLConnection).DeAllocateCursorHandle(FCursor);
  881. FreeAndNil(FMasterLink);
  882. FreeAndNil(FParams);
  883. FreeAndNil(FSQL);
  884. FreeAndNil(FInsertSQL);
  885. FreeAndNil(FDeleteSQL);
  886. FreeAndNil(FUpdateSQL);
  887. FreeAndNil(FIndexDefs);
  888. inherited Destroy;
  889. end;
  890. procedure TSQLQuery.SetReadOnly(AValue : Boolean);
  891. begin
  892. CheckInactive;
  893. if not AValue then
  894. begin
  895. if FParseSQL then FReadOnly := False
  896. else DatabaseErrorFmt(SNoParseSQL,['Updating ']);
  897. end
  898. else FReadOnly := True;
  899. end;
  900. procedure TSQLQuery.SetParseSQL(AValue : Boolean);
  901. begin
  902. CheckInactive;
  903. if not AValue then
  904. begin
  905. FReadOnly := True;
  906. Filtered := False;
  907. FParseSQL := False;
  908. end
  909. else
  910. FParseSQL := True;
  911. end;
  912. procedure TSQLQuery.SetUsePrimaryKeyAsKey(AValue : Boolean);
  913. begin
  914. if not Active then FusePrimaryKeyAsKey := AValue
  915. else
  916. begin
  917. // Just temporary, this should be possible in the future
  918. DatabaseError(SActiveDataset);
  919. end;
  920. end;
  921. Procedure TSQLQuery.UpdateIndexDefs;
  922. begin
  923. if assigned(DataBase) then
  924. (DataBase as TSQLConnection).UpdateIndexDefs(FIndexDefs,FTableName);
  925. end;
  926. Procedure TSQLQuery.ApplyRecUpdate(UpdateKind : TUpdateKind);
  927. procedure UpdateWherePart(var sql_where : string;x : integer);
  928. begin
  929. if (pfInKey in Fields[x].ProviderFlags) or
  930. ((FUpdateMode = upWhereAll) and (pfInWhere in Fields[x].ProviderFlags)) or
  931. ((FUpdateMode = UpWhereChanged) and (pfInWhere in Fields[x].ProviderFlags) and (fields[x].value <> fields[x].oldvalue)) then
  932. sql_where := sql_where + '(' + fields[x].FieldName + '= :OLD_' + fields[x].FieldName + ') and ';
  933. end;
  934. function ModifyRecQuery : string;
  935. var x : integer;
  936. sql_set : string;
  937. sql_where : string;
  938. begin
  939. sql_set := '';
  940. sql_where := '';
  941. for x := 0 to Fields.Count -1 do
  942. begin
  943. UpdateWherePart(sql_where,x);
  944. if (pfInUpdate in Fields[x].ProviderFlags) then
  945. sql_set := sql_set + fields[x].FieldName + '=:' + fields[x].FieldName + ',';
  946. end;
  947. setlength(sql_set,length(sql_set)-1);
  948. if length(sql_where) = 0 then DatabaseError(sNoWhereFields,self);
  949. setlength(sql_where,length(sql_where)-5);
  950. result := 'update ' + FTableName + ' set ' + sql_set + ' where ' + sql_where;
  951. end;
  952. function InsertRecQuery : string;
  953. var x : integer;
  954. sql_fields : string;
  955. sql_values : string;
  956. begin
  957. sql_fields := '';
  958. sql_values := '';
  959. for x := 0 to Fields.Count -1 do
  960. begin
  961. if not fields[x].IsNull then
  962. begin
  963. sql_fields := sql_fields + fields[x].FieldName + ',';
  964. sql_values := sql_values + ':' + fields[x].FieldName + ',';
  965. end;
  966. end;
  967. setlength(sql_fields,length(sql_fields)-1);
  968. setlength(sql_values,length(sql_values)-1);
  969. result := 'insert into ' + FTableName + ' (' + sql_fields + ') values (' + sql_values + ')';
  970. end;
  971. function DeleteRecQuery : string;
  972. var x : integer;
  973. sql_where : string;
  974. begin
  975. sql_where := '';
  976. for x := 0 to Fields.Count -1 do
  977. UpdateWherePart(sql_where,x);
  978. if length(sql_where) = 0 then DatabaseError(sNoWhereFields,self);
  979. setlength(sql_where,length(sql_where)-5);
  980. result := 'delete from ' + FTableName + ' where ' + sql_where;
  981. end;
  982. var qry : tsqlquery;
  983. x : integer;
  984. Fld : TField;
  985. begin
  986. case UpdateKind of
  987. ukModify : begin
  988. qry := FUpdateQry;
  989. if trim(qry.sql.Text) = '' then qry.SQL.Add(ModifyRecQuery);
  990. end;
  991. ukInsert : begin
  992. qry := FInsertQry;
  993. if trim(qry.sql.Text) = '' then qry.SQL.Add(InsertRecQuery);
  994. end;
  995. ukDelete : begin
  996. qry := FDeleteQry;
  997. if trim(qry.sql.Text) = '' then qry.SQL.Add(DeleteRecQuery);
  998. end;
  999. end;
  1000. with qry do
  1001. begin
  1002. for x := 0 to Params.Count-1 do with params[x] do if leftstr(name,4)='OLD_' then
  1003. begin
  1004. Fld := self.FieldByName(copy(name,5,length(name)-4));
  1005. AssignFieldValue(Fld,Fld.OldValue);
  1006. end
  1007. else
  1008. begin
  1009. Fld := self.FieldByName(name);
  1010. AssignFieldValue(Fld,Fld.Value);
  1011. end;
  1012. execsql;
  1013. end;
  1014. end;
  1015. Function TSQLQuery.GetCanModify: Boolean;
  1016. begin
  1017. // the test for assigned(FCursor) is needed for the case that the dataset isn't opened
  1018. if assigned(FCursor) and (FCursor.FStatementType = stSelect) then
  1019. Result:= Active and FUpdateable and (not FReadOnly)
  1020. else
  1021. Result := False;
  1022. end;
  1023. function TSQLQuery.GetIndexDefs : TIndexDefs;
  1024. begin
  1025. Result := FIndexDefs;
  1026. end;
  1027. procedure TSQLQuery.SetIndexDefs(AValue : TIndexDefs);
  1028. begin
  1029. FIndexDefs := AValue;
  1030. end;
  1031. procedure TSQLQuery.SetUpdateMode(AValue : TUpdateMode);
  1032. begin
  1033. FUpdateMode := AValue;
  1034. end;
  1035. procedure TSQLQuery.SetSchemaInfo( SchemaType : TSchemaType; SchemaObjectName, SchemaPattern : string);
  1036. begin
  1037. ReadOnly := True;
  1038. SQL.Clear;
  1039. SQL.Add((DataBase as tsqlconnection).GetSchemaInfoSQL(SchemaType, SchemaObjectName, SchemaPattern));
  1040. end;
  1041. procedure TSQLQuery.LoadBlobIntoStream(Field: TField;AStream: TMemoryStream);
  1042. begin
  1043. (DataBase as tsqlconnection).LoadBlobIntoStream(Field, AStream, FCursor,(Transaction as tsqltransaction));
  1044. end;
  1045. function TSQLQuery.GetStatementType : TStatementType;
  1046. begin
  1047. if assigned(FCursor) then Result := FCursor.FStatementType
  1048. else Result := stNone;
  1049. end;
  1050. Procedure TSQLQuery.SetDataSource(AVAlue : TDatasource);
  1051. Var
  1052. DS : TDatasource;
  1053. begin
  1054. DS:=DataSource;
  1055. If (AValue<>DS) then
  1056. begin
  1057. If Assigned(DS) then
  1058. DS.RemoveFreeNotification(Self);
  1059. If Assigned(AValue) then
  1060. begin
  1061. AValue.FreeNotification(Self);
  1062. FMasterLink:=TMasterParamsDataLink.Create(Self);
  1063. FMasterLink.Datasource:=AValue;
  1064. end
  1065. else
  1066. FreeAndNil(FMasterLink);
  1067. end;
  1068. end;
  1069. Function TSQLQuery.GetDataSource : TDatasource;
  1070. begin
  1071. If Assigned(FMasterLink) then
  1072. Result:=FMasterLink.DataSource
  1073. else
  1074. Result:=Nil;
  1075. end;
  1076. procedure TSQLQuery.Notification(AComponent: TComponent; Operation: TOperation);
  1077. begin
  1078. Inherited;
  1079. If (Operation=opRemove) and (AComponent=DataSource) then
  1080. DataSource:=Nil;
  1081. end;
  1082. { TSQLScript }
  1083. procedure TSQLScript.SetScript(const AValue: TStrings);
  1084. begin
  1085. FScript.assign(AValue);
  1086. end;
  1087. procedure TSQLScript.SetDatabase(Value: TDatabase);
  1088. begin
  1089. FDatabase := Value;
  1090. end;
  1091. procedure TSQLScript.SetTransaction(Value: TDBTransaction);
  1092. begin
  1093. FTransaction := Value;
  1094. end;
  1095. procedure TSQLScript.CheckDatabase;
  1096. begin
  1097. If (FDatabase=Nil) then
  1098. DatabaseError(SErrNoDatabaseAvailable,Self)
  1099. end;
  1100. constructor TSQLScript.Create(AOwner: TComponent);
  1101. begin
  1102. inherited Create(AOwner);
  1103. FScript := TStringList.Create;
  1104. FQuery := TSQLQuery.Create(nil);
  1105. end;
  1106. destructor TSQLScript.Destroy;
  1107. begin
  1108. FScript.Free;
  1109. FQuery.Free;
  1110. inherited Destroy;
  1111. end;
  1112. procedure TSQLScript.ExecuteScript;
  1113. var BufStr : String;
  1114. pBufStatStart,
  1115. pBufPos : PChar;
  1116. Statement : String;
  1117. begin
  1118. FQuery.DataBase := FDatabase;
  1119. FQuery.Transaction := FTransaction;
  1120. BufStr := FScript.Text;
  1121. pBufPos := @BufStr[1];
  1122. repeat
  1123. pBufStatStart := pBufPos;
  1124. repeat
  1125. inc(pBufPos);
  1126. until (pBufPos^ = ';') or (pBufPos^ = #0);
  1127. SetLength(statement,pbufpos-pBufStatStart);
  1128. move(pBufStatStart^,Statement[1],pbufpos-pBufStatStart);
  1129. if trim(statement) <> '' then
  1130. begin
  1131. fquery.SQL.Text := Statement;
  1132. fquery.ExecSQL;
  1133. inc(pBufPos);
  1134. end;
  1135. until pBufPos^ = #0;
  1136. end;
  1137. { TSQLCursor }
  1138. constructor TSQLCursor.Create;
  1139. begin
  1140. FBlobStrings := TStringList.Create;
  1141. inherited;
  1142. end;
  1143. destructor TSQLCursor.Destroy;
  1144. begin
  1145. FBlobStrings.Free;
  1146. inherited Destroy;
  1147. end;
  1148. end.