sqldb.pp 38 KB

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