memds.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  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. {$mode objfpc}
  11. {$H+}
  12. {
  13. TMemDataset : In-memory dataset.
  14. - Has possibility to copy Structure/Data from other dataset.
  15. - Can load/save to/from stream.
  16. Ideas taken from THKMemTab Component by Harri Kasulke - Hamburg/Germany
  17. E-mail: [email protected]
  18. }
  19. unit memds;
  20. interface
  21. uses
  22. SysUtils, Classes, DB;
  23. Const
  24. // Stream Markers.
  25. MarkerSize = SizeOf(Integer);
  26. smEOF = 0;
  27. smFieldDefs = 1;
  28. smData = 2;
  29. type
  30. MDSError=class(Exception);
  31. PRecInfo=^TMTRecInfo;
  32. TMTRecInfo=record
  33. Bookmark: Longint;
  34. BookmarkFlag: TBookmarkFlag;
  35. end;
  36. PInteger = ^Integer;
  37. PSmallInt = ^SmallInt;
  38. PInt64 = ^Int64;
  39. PFloat = ^Extended;
  40. PBoolean = ^Boolean;
  41. TMemDataset=class(TDataSet)
  42. private
  43. FOpenStream : TStream;
  44. FFileName : String;
  45. FModified : Boolean;
  46. FStream: TMemoryStream;
  47. FRecInfoOffset: integer;
  48. FRecInfoSize: integer;
  49. FRecCount: integer;
  50. FRecSize: integer;
  51. FRecBufferSize: integer;
  52. FCurrRecNo: integer;
  53. FIsOpen: boolean;
  54. FFilterBuffer: PChar;
  55. protected
  56. // Mandatory
  57. function AllocRecordBuffer: PChar; override;
  58. procedure FreeRecordBuffer(var Buffer: PChar); override;
  59. procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override;
  60. function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override;
  61. function GetFieldData(Field: TField; Buffer: Pointer): Boolean; override;
  62. function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;
  63. function GetRecordSize: Word; override;
  64. procedure InternalAddRecord(Buffer: Pointer; DoAppend: Boolean); override;
  65. procedure InternalClose; override;
  66. procedure InternalDelete; override;
  67. procedure InternalFirst; override;
  68. procedure InternalGotoBookmark(ABookmark: Pointer); override;
  69. procedure InternalInitFieldDefs; override;
  70. procedure InternalInitRecord(Buffer: PChar); override;
  71. procedure InternalLast; override;
  72. procedure InternalOpen; override;
  73. procedure InternalPost; override;
  74. procedure InternalSetToRecord(Buffer: PChar); override;
  75. function IsCursorOpen: Boolean; override;
  76. procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override;
  77. procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override;
  78. procedure SetFieldData(Field: TField; Buffer: Pointer); override;
  79. // Optional.
  80. function GetRecordCount: Integer; override;
  81. procedure SetRecNo(Value: Integer); override;
  82. function GetRecNo: Integer; override;
  83. // Own.
  84. Procedure RaiseError(Fmt : String; Args : Array of const);
  85. Procedure CheckMarker(F : TStream; Marker : Integer);
  86. Procedure WriteMarker(F : TStream; Marker : Integer);
  87. procedure ReadFieldDefsFromStream(F : TStream);
  88. procedure SaveFieldDefsToStream(F : TStream);
  89. // These should be overridden if you want to load more data.
  90. // E.g. index defs.
  91. Procedure LoadDataFromStream(F : TStream); virtual;
  92. // If SaveData=False, a size 0 block should be written.
  93. Procedure SaveDataToStream(F : TStream; SaveData : Boolean); virtual;
  94. private
  95. function MDSGetRecordOffset(ARecNo: integer): longint;
  96. function MDSGetFieldOffset(FieldNo: integer): integer;
  97. function MDSGetFieldSize(FieldNo: integer): integer;
  98. function MDSGetActiveBuffer(var Buffer: PChar): Boolean;
  99. procedure MDSReadRecord(Buffer:PChar;ARecNo:Integer);
  100. procedure MDSWriteRecord(Buffer:PChar;ARecNo:Integer);
  101. procedure MDSAppendRecord(Buffer:PChar);
  102. function MDSFilterRecord(Buffer: PChar): Boolean;
  103. public
  104. constructor Create(AOwner:tComponent); override;
  105. destructor Destroy; override;
  106. procedure CreateTable;
  107. Function DataSize : Integer;
  108. procedure Clear(ClearDefs : Boolean);
  109. procedure Clear;
  110. Procedure SaveToFile(AFileName : String);
  111. Procedure SaveToFile(AFileName : String; SaveData : Boolean);
  112. Procedure SaveToStream(F : TStream);
  113. Procedure SaveToStream(F : TStream; SaveData : Boolean);
  114. Procedure LoadFromStream(F : TStream);
  115. Procedure LoadFromFile(AFileName : String);
  116. Procedure CopyFromDataset(DataSet : TDataSet);
  117. Procedure CopyFromDataset(DataSet : TDataSet; CopyData : Boolean);
  118. Property Modified : Boolean Read FModified;
  119. published
  120. Property FileName : String Read FFileName Write FFileName;
  121. property Filtered;
  122. Property Active;
  123. Property FieldDefs;
  124. property BeforeOpen;
  125. property AfterOpen;
  126. property BeforeClose;
  127. property AfterClose;
  128. property BeforeInsert;
  129. property AfterInsert;
  130. property BeforeEdit;
  131. property AfterEdit;
  132. property BeforePost;
  133. property AfterPost;
  134. property BeforeCancel;
  135. property AfterCancel;
  136. property BeforeDelete;
  137. property AfterDelete;
  138. property BeforeScroll;
  139. property AfterScroll;
  140. property OnDeleteError;
  141. property OnEditError;
  142. property OnNewRecord;
  143. property OnPostError;
  144. property OnFilterRecord;
  145. end;
  146. implementation
  147. ResourceString
  148. SErrFieldTypeNotSupported = 'Fieldtype of Field "%s" not supported.';
  149. SErrBookMarkNotFound = 'Bookmark %d not found.';
  150. SErrInvalidDataStream = 'Error in data stream at position %d';
  151. SErrInvalidMarkerAtPos = 'Wrong data stream marker at position %d. Got %d, expected %d';
  152. SErrNoFileName = 'Filename must not be empty.';
  153. { ---------------------------------------------------------------------
  154. Stream functions
  155. ---------------------------------------------------------------------}
  156. Function ReadInteger(S : TStream) : Integer;
  157. begin
  158. S.ReadBuffer(Result,SizeOf(Result));
  159. end;
  160. Function ReadString(S : TStream) : String;
  161. Var
  162. L : Integer;
  163. begin
  164. L:=ReadInteger(S);
  165. Setlength(Result,L);
  166. If (L<>0) then
  167. S.ReadBuffer(Result[1],L);
  168. end;
  169. Procedure WriteInteger(S : TStream; Value : Integer);
  170. begin
  171. S.WriteBuffer(Value,SizeOf(Value));
  172. end;
  173. Procedure WriteString(S : TStream; Value : String);
  174. Var
  175. L : Integer;
  176. begin
  177. L:=Length(Value);
  178. WriteInteger(S,Length(Value));
  179. If (L<>0) then
  180. S.WriteBuffer(Value[1],L);
  181. end;
  182. { ---------------------------------------------------------------------
  183. TMemDataset
  184. ---------------------------------------------------------------------}
  185. constructor TMemDataset.Create(AOwner:tComponent);
  186. begin
  187. inherited create(aOwner);
  188. FStream:=TMemoryStream.Create;
  189. FRecInfoSize:=SizeOf(TMTRecInfo);
  190. FRecCount:=0;
  191. FRecSize:=0;
  192. FRecBufferSize:=0;
  193. FRecInfoOffset:=0;
  194. FCurrRecNo:=-1;
  195. FIsOpen:=False;
  196. end;
  197. Destructor TMemDataset.Destroy;
  198. begin
  199. FStream.Free;
  200. inherited Destroy;
  201. end;
  202. function TMemDataset.MDSGetRecordOffset(ARecNo: integer): longint;
  203. begin
  204. Result:=FRecSize*ARecNo
  205. end;
  206. function TMemDataset.MDSGetFieldOffset(FieldNo: integer): integer;
  207. var
  208. I : integer;
  209. begin
  210. Result:=0;
  211. for I:=1 to FieldNo-1 do
  212. Result:=Result+MDSGetFieldSize(I);
  213. end;
  214. Procedure TMemDataset.RaiseError(Fmt : String; Args : Array of const);
  215. begin
  216. Raise MDSError.CreateFmt(Fmt,Args);
  217. end;
  218. function TMemDataset.MDSGetFieldSize(FieldNo: integer): integer;
  219. begin
  220. case FieldDefs.Items[FieldNo-1].Datatype of
  221. ftString: result:=FieldDefs.Items[FieldNo-1].Size+1;
  222. ftBoolean: result:=SizeOf(Boolean);
  223. ftFloat: result:=SizeOf(Extended);
  224. ftLargeInt: result:=SizeOf(int64);
  225. ftSmallInt: result:=SizeOf(SmallInt);
  226. ftInteger: result:=SizeOf(Integer);
  227. ftDate: result:=SizeOf(TDateTime);
  228. ftTime: result:=SizeOf(TDateTime);
  229. else
  230. RaiseError(SErrFieldTypeNotSupported,[FieldDefs.Items[FieldNo-1].Name]);
  231. end;
  232. end;
  233. function TMemDataset.MDSGetActiveBuffer(var Buffer: PChar): Boolean;
  234. begin
  235. case State of
  236. dsBrowse:
  237. if IsEmpty then
  238. Buffer:=nil
  239. else
  240. Buffer:=ActiveBuffer;
  241. dsEdit,
  242. dsInsert:
  243. Buffer:=ActiveBuffer;
  244. dsFilter:
  245. Buffer:=FFilterBuffer;
  246. else
  247. Buffer:=nil;
  248. end;
  249. Result:=(Buffer<>nil);
  250. end;
  251. procedure TMemDataset.MDSReadRecord(Buffer:PChar;ARecNo:Integer); //Reads a Rec from Stream in Buffer
  252. begin
  253. FStream.Position:=MDSGetRecordOffset(ARecNo);
  254. FStream.ReadBuffer(Buffer^, FRecSize);
  255. end;
  256. procedure TMemDataset.MDSWriteRecord(Buffer:PChar;ARecNo:Integer); //Writes a Rec from Buffer to Stream
  257. begin
  258. FStream.Position:=MDSGetRecordOffset(ARecNo);
  259. FStream.WriteBuffer(Buffer^, FRecSize);
  260. FModified:=True;
  261. end;
  262. procedure TMemDataset.MDSAppendRecord(Buffer:PChar); //Appends a Rec (from Buffer) to Stream
  263. begin
  264. FStream.Position:=MDSGetRecordOffset(FRecCount);
  265. FStream.WriteBuffer(Buffer^, FRecSize);
  266. FModified:=True;
  267. end;
  268. //Abstract Overrides
  269. function TMemDataset.AllocRecordBuffer: PChar;
  270. begin
  271. GetMem(Result,FRecBufferSize);
  272. end;
  273. procedure TMemDataset.FreeRecordBuffer (var Buffer: PChar);
  274. begin
  275. FreeMem(Buffer);
  276. end;
  277. procedure TMemDataset.InternalInitRecord(Buffer: PChar);
  278. var
  279. I : integer;
  280. begin
  281. for I:=1 to FieldCount do
  282. case FieldDefs.Items[I-1].Datatype of
  283. ftString: pChar(Buffer+MDSGetFieldOffset(I))^:=#0;
  284. ftBoolean: pBoolean(Buffer+MDSGetFieldOffset(I))^:=False;
  285. ftFloat: pFloat(Buffer+MDSGetFieldOffset(I))^:=0;
  286. ftLargeint: PInt64(Buffer+MDSGetFieldOffset(I))^:=0;
  287. ftSmallInt: pSmallInt(Buffer+MDSGetFieldOffset(I))^:=0;
  288. ftInteger: pInteger(Buffer+MDSGetFieldOffset(I))^:=0;
  289. ftCurrency: pFloat(Buffer+MDSGetFieldOffset(I))^:=0;
  290. ftDate: pFloat(Buffer+MDSGetFieldOffset(I))^:=0;
  291. ftTime: pFloat(Buffer+MDSGetFieldOffset(I))^:=0;
  292. ftDateTime: pFloat(Buffer+MDSGetFieldOffset(I))^:=0;
  293. end;
  294. end;
  295. procedure TMemDataset.InternalDelete;
  296. Var
  297. TS : TMemoryStream;
  298. OldPos,NewPos,CopySize1,CopySize2 : Cardinal;
  299. begin
  300. if (FCurrRecNo<0) or (FCurrRecNo>=FRecCount) then
  301. Exit;
  302. // Very inefficient. We should simply move the last part closer to the beginning in
  303. // The FStream.
  304. TS:=TMemoryStream.Create;
  305. Try
  306. if FCurrRecNo>0 then
  307. begin
  308. FStream.Position:=MDSGetRecordOffset(0); //Delete Rec
  309. if FCurrRecNo<FRecCount-1 then
  310. begin
  311. TS.CopyFrom(FStream, MDSGetRecordOffset(FCurrRecNo)-MDSGetRecordOffset(0));
  312. FStream.Position:=MDSGetRecordOffset(FCurrRecNo+1);
  313. TS.CopyFrom(FStream,(MDSGetRecordOffset(FRecCount))-MDSGetRecordOffset(FCurrRecNo+1));
  314. end
  315. else
  316. TS.CopyFrom(FStream,MDSGetRecordOffset(FRecCount-1));
  317. end
  318. else
  319. begin //Delete first Rec
  320. FStream.Position:=MDSGetRecordOffset(FCurrRecNo+1);
  321. TS.CopyFrom(FStream,(MDSGetRecordOffset(FRecCount))-MDSGetRecordOffset(FCurrRecNo+1));
  322. end;
  323. FStream.loadFromStream(TS);
  324. Dec(FRecCount);
  325. if FRecCount=0 then
  326. FCurrRecNo:=-1
  327. else
  328. if FCurrRecNo>=FRecCount then FCurrRecNo:=FRecCount-1;
  329. Finally
  330. TS.Free;
  331. end;
  332. FModified:=True;
  333. end;
  334. procedure TMemDataset.InternalInitFieldDefs;
  335. begin
  336. If (FOpenStream<>Nil) then
  337. ReadFieldDefsFromStream(FOpenStream);
  338. end;
  339. Procedure TMemDataset.CheckMarker(F : TStream; Marker : Integer);
  340. Var
  341. I,P : Integer;
  342. begin
  343. P:=F.Position;
  344. If F.Read(I,MarkerSize)<>MarkerSize then
  345. RaiseError(SErrInvalidDataStream,[P])
  346. else
  347. if (I<>Marker) then
  348. RaiseError(SErrInvalidMarkerAtPos,[P,I,Marker]);
  349. end;
  350. procedure TMemDataset.ReadFieldDefsFromStream(F : TStream);
  351. Var
  352. I,ACount : Integer;
  353. FN : String;
  354. FS : Integer;
  355. B : Boolean;
  356. FT : TFieldType;
  357. begin
  358. CheckMarker(F,smFieldDefs);
  359. FieldDefs.Clear;
  360. ACount:=ReadInteger(F);
  361. For I:=1 to ACount do
  362. begin
  363. FN:=ReadString(F);
  364. FS:=ReadInteger(F);
  365. FT:=TFieldType(ReadInteger(F));
  366. B:=ReadInteger(F)<>0;
  367. TFieldDef.Create(FieldDefs,FN,ft,FS,B,I);
  368. end;
  369. CreateTable;
  370. end;
  371. procedure TMemDataset.InternalFirst;
  372. begin
  373. FCurrRecNo:=-1;
  374. end;
  375. procedure TMemDataset.InternalLast;
  376. begin
  377. FCurrRecNo:=FRecCount;
  378. end;
  379. procedure TMemDataset.InternalOpen;
  380. begin
  381. If (FFileName<>'') then
  382. FOpenStream:=TFileStream.Create(FFileName,fmOpenRead);
  383. Try
  384. InternalInitFieldDefs;
  385. if DefaultFields then
  386. CreateFields;
  387. BindFields(True);
  388. FCurrRecNo:=-1;
  389. If (FOpenStream<>Nil) then
  390. begin
  391. LoadDataFromStream(FOpenStream);
  392. CheckMarker(FOpenStream,smEOF);
  393. end;
  394. Finally
  395. FreeAndNil(FOpenStream);
  396. end;
  397. FIsOpen:=True;
  398. end;
  399. Procedure TMemDataSet.LoadDataFromStream(F : TStream);
  400. Var
  401. Size : Integer;
  402. begin
  403. CheckMarker(F,smData);
  404. Size:=ReadInteger(F);
  405. FStream.Clear;
  406. FStream.CopyFrom(F,Size);
  407. FRecCount:=Size div FRecSize;
  408. FCurrRecNo:=-1;
  409. end;
  410. Procedure TMemDataSet.LoadFromStream(F : TStream);
  411. begin
  412. Close;
  413. ReadFieldDefsFromStream(F);
  414. LoadDataFromStream(F);
  415. CheckMarker(F,smEOF);
  416. FModified:=False;
  417. end;
  418. Procedure TMemDataSet.LoadFromFile(AFileName : String);
  419. Var
  420. F : TFileStream;
  421. begin
  422. F:=TFileStream.Create(AFileName,fmOpenRead);
  423. Try
  424. LoadFromStream(F);
  425. Finally
  426. F.Free;
  427. end;
  428. end;
  429. Procedure TMemDataset.SaveToFile(AFileName : String);
  430. begin
  431. SaveToFile(AFileName,True);
  432. end;
  433. Procedure TMemDataset.SaveToFile(AFileName : String; SaveData : Boolean);
  434. Var
  435. F : TFileStream;
  436. begin
  437. If (AFileName='') then
  438. RaiseError(SErrNoFileName,[]);
  439. F:=TFileStream.Create(AFileName,fmCreate);
  440. try
  441. SaveToStream(F,SaveData);
  442. Finally
  443. F.Free;
  444. end;
  445. end;
  446. Procedure TMemDataset.WriteMarker(F : TStream; Marker : Integer);
  447. begin
  448. Writeinteger(F,Marker);
  449. end;
  450. Procedure TMemDataset.SaveToStream(F : TStream);
  451. begin
  452. SaveToStream(F,True);
  453. end;
  454. Procedure TMemDataset.SaveToStream(F : TStream; SaveData : Boolean);
  455. begin
  456. SaveFieldDefsToStream(F);
  457. If SaveData then
  458. SaveDataToStream(F,SaveData);
  459. WriteMarker(F,smEOF);
  460. end;
  461. Procedure TMemDataset.SaveFieldDefsToStream(F : TStream);
  462. Var
  463. I,ACount : Integer;
  464. FN : String;
  465. FS : Integer;
  466. B : Boolean;
  467. FT : TFieldType;
  468. FD : TFieldDef;
  469. begin
  470. WriteMarker(F,smFieldDefs);
  471. WriteInteger(F,FieldDefs.Count);
  472. For I:=1 to FieldDefs.Count do
  473. begin
  474. FD:=FieldDefs[I-1];
  475. WriteString(F,FD.Name);
  476. WriteInteger(F,FD.Size);
  477. WriteInteger(F,Ord(FD.DataType));
  478. WriteInteger(F,Ord(FD.Required));
  479. end;
  480. end;
  481. Procedure TMemDataset.SaveDataToStream(F : TStream; SaveData : Boolean);
  482. begin
  483. if SaveData then
  484. begin
  485. WriteMarker(F,smData);
  486. WriteInteger(F,FStream.Size);
  487. FStream.Position:=0;
  488. F.CopyFrom(FStream,FStream.Size);
  489. FModified:=False;
  490. end
  491. else
  492. begin
  493. WriteMarker(F,smData);
  494. WriteInteger(F,0);
  495. end;
  496. end;
  497. procedure TMemDataset.InternalClose;
  498. begin
  499. if (FModified) and (FFileName<>'') then
  500. SaveToFile(FFileName,True);
  501. FIsOpen:=False;
  502. FModified:=False;
  503. BindFields(False);
  504. if DefaultFields then
  505. DestroyFields;
  506. end;
  507. procedure TMemDataset.InternalPost;
  508. begin
  509. CheckActive;
  510. if ((State<>dsEdit) and (State<>dsInsert)) then
  511. Exit;
  512. if (State=dsEdit) then
  513. MDSWriteRecord(ActiveBuffer, FCurrRecNo)
  514. else
  515. InternalAddRecord(ActiveBuffer,True);
  516. end;
  517. function TMemDataset.IsCursorOpen: Boolean;
  518. begin
  519. Result:=FIsOpen;
  520. end;
  521. function TMemDataset.GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
  522. var
  523. Accepted: Boolean;
  524. begin
  525. Result:=grOk;
  526. Accepted:=False;
  527. if (FRecCount<1) then
  528. begin
  529. Result:=grEOF;
  530. exit;
  531. end;
  532. repeat
  533. case GetMode of
  534. gmCurrent:
  535. if (FCurrRecNo>=FRecCount) or (FCurrRecNo<0) then
  536. Result:=grError;
  537. gmNext:
  538. if (FCurrRecNo<FRecCount-1) then
  539. Inc(FCurrRecNo)
  540. else
  541. Result:=grEOF;
  542. gmPrior:
  543. if (FCurrRecNo>0) then
  544. Dec(FCurrRecNo)
  545. else
  546. result:=grBOF;
  547. end;
  548. if result=grOK then
  549. begin
  550. MDSReadRecord(Buffer, FCurrRecNo);
  551. PRecInfo(Buffer+FRecInfoOffset)^.Bookmark:=FCurrRecNo;
  552. PRecInfo(Buffer+FRecInfoOffset)^.BookmarkFlag:=bfCurrent;
  553. if (Filtered) then
  554. Accepted:=MDSFilterRecord(Buffer) //Filtering
  555. else
  556. Accepted:=True;
  557. if (GetMode=gmCurrent) and not Accepted then
  558. result:=grError;
  559. end;
  560. until (result<>grOK) or Accepted;
  561. end;
  562. function TMemDataset.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
  563. var
  564. SrcBuffer: PChar;
  565. begin
  566. result:=False;
  567. if not MDSGetActiveBuffer(SrcBuffer) then
  568. Exit;
  569. if (Field.FieldNo>0) and (Assigned(Buffer)) and (Assigned(SrcBuffer)) then
  570. begin
  571. Move((SrcBuffer+MDSGetFieldOffset(Field.FieldNo))^, Buffer^, MDSGetFieldSize(Field.FieldNo));
  572. result:=True;
  573. end;
  574. end;
  575. procedure TMemDataset.SetFieldData(Field: TField; Buffer: Pointer);
  576. var
  577. DestBuffer: PChar;
  578. begin
  579. MDSGetActiveBuffer(DestBuffer);
  580. if (Field.FieldNo>0) and (Assigned(Buffer)) and (Assigned(DestBuffer)) then
  581. Move(Buffer^,(DestBuffer+MDSGetFieldOffset(Field.FieldNo))^, MDSGetFieldSize(Field.FieldNo));
  582. end;
  583. function TMemDataset.GetRecordSize: Word;
  584. begin
  585. Result:=FRecSize;
  586. end;
  587. procedure TMemDataset.InternalGotoBookmark(ABookmark: Pointer);
  588. var
  589. ReqBookmark: integer;
  590. begin
  591. ReqBookmark:=PInteger(ABookmark)^;
  592. if (ReqBookmark>=0) and (ReqBookmark<FRecCount) then
  593. FCurrRecNo:=ReqBookmark
  594. else
  595. RaiseError(SErrBookMarkNotFound,[ReqBookmark]);
  596. end;
  597. procedure TMemDataset.InternalSetToRecord(Buffer: PChar);
  598. var
  599. ReqBookmark: integer;
  600. begin
  601. ReqBookmark:=PRecInfo(Buffer+FRecInfoOffset)^.Bookmark;
  602. InternalGotoBookmark (@ReqBookmark);
  603. end;
  604. function TMemDataset.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
  605. begin
  606. Result:=PRecInfo(Buffer+FRecInfoOffset)^.BookmarkFlag;
  607. end;
  608. procedure TMemDataset.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
  609. begin
  610. PRecInfo(Buffer+FRecInfoOffset)^.BookmarkFlag := Value;
  611. end;
  612. procedure TMemDataset.GetBookmarkData(Buffer: PChar; Data: Pointer);
  613. begin
  614. if Data<>nil then
  615. PInteger(Data)^:=PRecInfo(Buffer+FRecInfoOffset)^.Bookmark;
  616. end;
  617. procedure TMemDataset.SetBookmarkData(Buffer: PChar; Data: Pointer);
  618. begin
  619. if Data<>nil then
  620. PRecInfo(Buffer+FRecInfoOffset)^.Bookmark:=PInteger(Data)^
  621. else
  622. PRecInfo(Buffer+FRecInfoOffset)^.Bookmark:=0;
  623. end;
  624. function TMemDataset.MDSFilterRecord(Buffer: PChar): Boolean;
  625. var
  626. SaveState: TDatasetState;
  627. begin
  628. Result:=True;
  629. if not Assigned(OnFilterRecord) then
  630. Exit;
  631. SaveState:=SetTempState(dsFilter);
  632. FFilterBuffer:=Buffer;
  633. OnFilterRecord(Self,Result);
  634. RestoreState(SaveState);
  635. end;
  636. Function TMemDataset.DataSize : Integer;
  637. begin
  638. Result:=FStream.Size;
  639. end;
  640. procedure TMemDataset.Clear;
  641. begin
  642. Clear(True);
  643. end;
  644. procedure TMemDataset.Clear(ClearDefs : Boolean);
  645. begin
  646. FStream.Clear;
  647. FRecCount:=0;
  648. FCurrRecNo:=-1;
  649. if Active then
  650. Resync([]);
  651. If ClearDefs then
  652. begin
  653. Close;
  654. FieldDefs.Clear;
  655. end;
  656. end;
  657. procedure TMemDataset.CreateTable;
  658. var
  659. I : integer;
  660. begin
  661. FStream.Clear;
  662. FRecCount:=0;
  663. FCurrRecNo:=-1;
  664. FIsOpen:=False;
  665. FRecSize:=0;
  666. for I:=1 to FieldDefs.Count do
  667. FRecSize:=FRecSize+MDSGetFieldSize(I);
  668. FRecInfoOffset:=FRecSize;
  669. FRecSize:=FRecSize+FRecInfoSize;
  670. FRecBufferSize:=FRecSize;
  671. end;
  672. procedure TMemDataset.InternalAddRecord(Buffer: Pointer; DoAppend: Boolean);
  673. begin
  674. MDSAppendRecord(ActiveBuffer);
  675. InternalLast;
  676. Inc(FRecCount);
  677. end;
  678. procedure TMemDataset.SetRecNo(Value: Integer);
  679. begin
  680. CheckBrowseMode;
  681. if (Value>1) and (Value<=FRecCount) then
  682. begin
  683. FCurrRecNo:=Value-1;
  684. Resync([]);
  685. end;
  686. end;
  687. Function TMemDataset.GetRecNo: Longint;
  688. begin
  689. UpdateCursorPos;
  690. if (FCurrRecNo<0) then
  691. Result:=1
  692. else
  693. Result:=FCurrRecNo+1;
  694. end;
  695. Function TMemDataset.GetRecordCount: Longint;
  696. begin
  697. CheckActive;
  698. Result:=FRecCount;
  699. end;
  700. Procedure TMemDataset.CopyFromDataset(DataSet : TDataSet);
  701. begin
  702. CopyFromDataset(Dataset,True);
  703. end;
  704. Procedure TMemDataset.CopyFromDataset(DataSet : TDataSet; CopyData : Boolean);
  705. Var
  706. I : Integer;
  707. F,F1,F2 : TField;
  708. L1,L2 : TList;
  709. N : String;
  710. begin
  711. Clear(True);
  712. // NOT from fielddefs. The data may not be available in buffers !!
  713. For I:=0 to Dataset.FieldCount-1 do
  714. begin
  715. F:=Dataset.Fields[I];
  716. TFieldDef.Create(FieldDefs,F.FieldName,F.DataType,F.Size,F.Required,F.FieldNo);
  717. end;
  718. CreateTable;
  719. If CopyData then
  720. begin
  721. Open;
  722. L1:=TList.Create;
  723. Try
  724. L2:=TList.Create;
  725. Try
  726. For I:=0 to FieldDefs.Count-1 do
  727. begin
  728. N:=FieldDefs[I].Name;
  729. F1:=FieldByName(N);
  730. F2:=DataSet.FieldByName(N);
  731. L1.Add(F1);
  732. L2.Add(F2);
  733. end;
  734. Dataset.DisableControls;
  735. Try
  736. Dataset.Open;
  737. While not Dataset.EOF do
  738. begin
  739. Append;
  740. For I:=0 to L1.Count-1 do
  741. begin
  742. F1:=TField(L1[i]);
  743. F2:=TField(L2[I]);
  744. Case F1.DataType of
  745. ftString : F1.AsString:=F2.AsString;
  746. ftBoolean : F1.AsBoolean:=F2.AsBoolean;
  747. ftFloat : F1.AsFloat:=F2.AsFloat;
  748. ftLargeInt : F1.AsInteger:=F2.AsInteger;
  749. ftSmallInt : F1.AsInteger:=F2.AsInteger;
  750. ftInteger : F1.AsInteger:=F2.AsInteger;
  751. ftDate : F1.AsDateTime:=F2.AsDateTime;
  752. ftTime : F1.AsDateTime:=F2.AsDateTime;
  753. end;
  754. end;
  755. Try
  756. Post;
  757. except
  758. Cancel;
  759. Raise;
  760. end;
  761. Dataset.Next;
  762. end;
  763. Finally
  764. Dataset.EnableControls;
  765. end;
  766. finally
  767. L2.Free;
  768. end;
  769. finally
  770. l1.Free;
  771. end;
  772. end;
  773. end;
  774. end.