bufdataset.pp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2006 by Joost van der Sluis, member of the
  4. Free Pascal development team
  5. BufDataset implementation
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit BufDataset;
  13. {$mode objfpc}
  14. {$h+}
  15. interface
  16. uses Classes,Sysutils,db,bufdataset_parser;
  17. type
  18. TBufDataset = Class;
  19. TResolverErrorEvent = procedure(Sender: TObject; DataSet: TBufDataset; E: EUpdateError;
  20. UpdateKind: TUpdateKind; var Response: TResolverResponse) of object;
  21. { TBufBlobStream }
  22. PBlobBuffer = ^TBlobBuffer;
  23. TBlobBuffer = record
  24. FieldNo : integer;
  25. OrgBufID: integer;
  26. Buffer : pointer;
  27. Size : ptrint;
  28. end;
  29. TBufBlobStream = class(TStream)
  30. private
  31. FBlobBuffer : PBlobBuffer;
  32. FPosition : ptrint;
  33. FDataset : TBufDataset;
  34. protected
  35. function Read(var Buffer; Count: Longint): Longint; override;
  36. function Write(const Buffer; Count: Longint): Longint; override;
  37. function Seek(Offset: Longint; Origin: Word): Longint; override;
  38. public
  39. constructor Create(Field: TBlobField; Mode: TBlobStreamMode);
  40. end;
  41. { TBufDataset }
  42. PBufRecLinkItem = ^TBufRecLinkItem;
  43. TBufRecLinkItem = record
  44. prior : PBufRecLinkItem;
  45. next : PBufRecLinkItem;
  46. end;
  47. PBufBookmark = ^TBufBookmark;
  48. TBufBookmark = record
  49. BookmarkData : PBufRecLinkItem;
  50. BookmarkFlag : TBookmarkFlag;
  51. end;
  52. PRecUpdateBuffer = ^TRecUpdateBuffer;
  53. TRecUpdateBuffer = record
  54. UpdateKind : TUpdateKind;
  55. BookmarkData : pointer;
  56. OldValuesBuffer : pchar;
  57. end;
  58. PBufBlobField = ^TBufBlobField;
  59. TBufBlobField = record
  60. ConnBlobBuffer : array[0..11] of byte; // It's here where the db-specific data is stored
  61. BlobBuffer : PBlobBuffer;
  62. end;
  63. TRecordsUpdateBuffer = array of TRecUpdateBuffer;
  64. TBufDataset = class(TDBDataSet)
  65. private
  66. FCurrentRecBuf : PBufRecLinkItem;
  67. FLastRecBuf : PBufRecLinkItem;
  68. FFirstRecBuf : PBufRecLinkItem;
  69. FFilterBuffer : pchar;
  70. FBRecordCount : integer;
  71. FPacketRecords : integer;
  72. FRecordSize : Integer;
  73. FNullmaskSize : byte;
  74. FOpen : Boolean;
  75. FUpdateBuffer : TRecordsUpdateBuffer;
  76. FCurrentUpdateBuffer : integer;
  77. FParser : TBufDatasetParser;
  78. FFieldBufPositions : array of longint;
  79. FAllPacketsFetched : boolean;
  80. FOnUpdateError : TResolverErrorEvent;
  81. FBlobBuffers : array of PBlobBuffer;
  82. FUpdateBlobBuffers: array of PBlobBuffer;
  83. function GetCurrentBuffer: PChar;
  84. procedure CalcRecordSize;
  85. function LoadBuffer(Buffer : PChar): TGetResult;
  86. function GetFieldSize(FieldDef : TFieldDef) : longint;
  87. function GetRecordUpdateBuffer : boolean;
  88. procedure SetPacketRecords(aValue : integer);
  89. function IntAllocRecordBuffer: PChar;
  90. procedure DoFilterRecord(var Acceptable: Boolean);
  91. procedure ParseFilter(const AFilter: string);
  92. protected
  93. function GetNewBlobBuffer : PBlobBuffer;
  94. function GetNewWriteBlobBuffer : PBlobBuffer;
  95. procedure SetRecNo(Value: Longint); override;
  96. function GetRecNo: Longint; override;
  97. function GetChangeCount: integer; virtual;
  98. function AllocRecordBuffer: PChar; override;
  99. procedure FreeRecordBuffer(var Buffer: PChar); override;
  100. procedure InternalInitRecord(Buffer: PChar); override;
  101. function GetCanModify: Boolean; override;
  102. function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;
  103. procedure InternalOpen; override;
  104. procedure InternalClose; override;
  105. function getnextpacket : integer;
  106. function GetRecordSize: Word; override;
  107. procedure InternalPost; override;
  108. procedure InternalCancel; Override;
  109. procedure InternalDelete; override;
  110. procedure InternalFirst; override;
  111. procedure InternalLast; override;
  112. procedure InternalSetToRecord(Buffer: PChar); override;
  113. procedure InternalGotoBookmark(ABookmark: Pointer); override;
  114. procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override;
  115. procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override;
  116. procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override;
  117. function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override;
  118. function IsCursorOpen: Boolean; override;
  119. function GetRecordCount: Longint; override;
  120. procedure ApplyRecUpdate(UpdateKind : TUpdateKind); virtual;
  121. procedure SetOnUpdateError(const aValue: TResolverErrorEvent);
  122. procedure SetFilterText(const Value: String); override; {virtual;}
  123. procedure SetFiltered(Value: Boolean); override; {virtual;}
  124. {abstracts, must be overidden by descendents}
  125. function Fetch : boolean; virtual; abstract;
  126. function LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; virtual; abstract;
  127. procedure LoadBlobIntoStream(Field: TField;AStream: TStream); virtual; abstract;
  128. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField); virtual; abstract;
  129. public
  130. constructor Create(AOwner: TComponent); override;
  131. function GetFieldData(Field: TField; Buffer: Pointer;
  132. NativeFormat: Boolean): Boolean; override;
  133. function GetFieldData(Field: TField; Buffer: Pointer): Boolean; override;
  134. procedure SetFieldData(Field: TField; Buffer: Pointer;
  135. NativeFormat: Boolean); override;
  136. procedure SetFieldData(Field: TField; Buffer: Pointer); override;
  137. procedure ApplyUpdates; virtual; overload;
  138. procedure ApplyUpdates(MaxErrors: Integer); virtual; overload;
  139. procedure CancelUpdates; virtual;
  140. destructor Destroy; override;
  141. function Locate(const keyfields: string; const keyvalues: Variant; options: TLocateOptions) : boolean; override;
  142. function UpdateStatus: TUpdateStatus; override;
  143. function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
  144. property ChangeCount : Integer read GetChangeCount;
  145. published
  146. property PacketRecords : Integer read FPacketRecords write SetPacketRecords default 10;
  147. property OnUpdateError: TResolverErrorEvent read FOnUpdateError write SetOnUpdateError;
  148. end;
  149. implementation
  150. uses variants, dbconst;
  151. { ---------------------------------------------------------------------
  152. TBufDataSet
  153. ---------------------------------------------------------------------}
  154. constructor TBufDataset.Create(AOwner : TComponent);
  155. begin
  156. Inherited Create(AOwner);
  157. SetLength(FUpdateBuffer,0);
  158. SetLength(FBlobBuffers,0);
  159. SetLength(FUpdateBlobBuffers,0);
  160. BookmarkSize := sizeof(TBufBookmark);
  161. FParser := nil;
  162. FPacketRecords := 10;
  163. end;
  164. procedure TBufDataset.SetPacketRecords(aValue : integer);
  165. begin
  166. if (aValue = -1) or (aValue > 0) then FPacketRecords := aValue
  167. else DatabaseError(SInvPacketRecordsValue);
  168. end;
  169. destructor TBufDataset.Destroy;
  170. begin
  171. inherited destroy;
  172. end;
  173. Function TBufDataset.GetCanModify: Boolean;
  174. begin
  175. Result:= False;
  176. end;
  177. function TBufDataset.intAllocRecordBuffer: PChar;
  178. begin
  179. // Note: Only the internal buffers of TDataset provide bookmark information
  180. result := AllocMem(FRecordsize+sizeof(TBufRecLinkItem));
  181. end;
  182. function TBufDataset.AllocRecordBuffer: PChar;
  183. begin
  184. result := AllocMem(FRecordsize + sizeof(TBufBookmark) + CalcfieldsSize);
  185. // The records are initialised, or else the fields of an empty, just-opened dataset
  186. // are not null
  187. InitRecord(result);
  188. end;
  189. procedure TBufDataset.FreeRecordBuffer(var Buffer: PChar);
  190. begin
  191. ReAllocMem(Buffer,0);
  192. end;
  193. procedure TBufDataset.InternalOpen;
  194. begin
  195. CalcRecordSize;
  196. FBRecordcount := 0;
  197. FFirstRecBuf := pointer(IntAllocRecordBuffer);
  198. FLastRecBuf := FFirstRecBuf;
  199. FCurrentRecBuf := FLastRecBuf;
  200. FAllPacketsFetched := False;
  201. FOpen:=True;
  202. // parse filter expression
  203. try
  204. ParseFilter(Filter);
  205. except
  206. // oops, a problem with parsing, clear filter for now
  207. on E: Exception do Filter := EmptyStr;
  208. end;
  209. end;
  210. procedure TBufDataset.InternalClose;
  211. var pc : pchar;
  212. r : integer;
  213. begin
  214. FOpen:=False;
  215. FCurrentRecBuf := FFirstRecBuf;
  216. while assigned(FCurrentRecBuf) do
  217. begin
  218. pc := pointer(FCurrentRecBuf);
  219. FCurrentRecBuf := FCurrentRecBuf^.next;
  220. FreeRecordBuffer(pc);
  221. end;
  222. if Length(FUpdateBuffer) > 0 then
  223. begin
  224. for r := 0 to length(FUpdateBuffer)-1 do with FUpdateBuffer[r] do
  225. begin
  226. if assigned(BookmarkData) then
  227. FreeRecordBuffer(OldValuesBuffer);
  228. end;
  229. end;
  230. SetLength(FUpdateBuffer,0);
  231. FFirstRecBuf:= nil;
  232. SetLength(FFieldBufPositions,0);
  233. if assigned(FParser) then FreeAndNil(FParser);
  234. end;
  235. procedure TBufDataset.InternalFirst;
  236. begin
  237. // if FCurrentRecBuf = FLastRecBuf then the dataset is just opened and empty
  238. // in which case InternalFirst should do nothing (bug 7211)
  239. if FCurrentRecBuf <> FLastRecBuf then
  240. FCurrentRecBuf := nil;
  241. end;
  242. procedure TBufDataset.InternalLast;
  243. begin
  244. repeat
  245. until (getnextpacket < FPacketRecords) or (FPacketRecords = -1);
  246. if FLastRecBuf <> FFirstRecBuf then
  247. FCurrentRecBuf := FLastRecBuf;
  248. end;
  249. procedure unSetFieldIsNull(NullMask : pbyte;x : longint); //inline;
  250. begin
  251. NullMask[x div 8] := (NullMask[x div 8]) and not (1 shl (x mod 8));
  252. end;
  253. procedure SetFieldIsNull(NullMask : pbyte;x : longint); //inline;
  254. begin
  255. NullMask[x div 8] := (NullMask[x div 8]) or (1 shl (x mod 8));
  256. end;
  257. function GetFieldIsNull(NullMask : pbyte;x : longint) : boolean; //inline;
  258. begin
  259. result := ord(NullMask[x div 8]) and (1 shl (x mod 8)) > 0
  260. end;
  261. function TBufDataset.GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
  262. var Acceptable : Boolean;
  263. SaveState: TDataSetState;
  264. begin
  265. Result := grOK;
  266. repeat
  267. Acceptable := True;
  268. case GetMode of
  269. gmPrior :
  270. if not assigned(PBufRecLinkItem(FCurrentRecBuf)^.prior) then
  271. begin
  272. Result := grBOF;
  273. end
  274. else
  275. begin
  276. FCurrentRecBuf := PBufRecLinkItem(FCurrentRecBuf)^.prior;
  277. end;
  278. gmCurrent :
  279. if FCurrentRecBuf = FLastRecBuf then
  280. Result := grError;
  281. gmNext :
  282. if FCurrentRecBuf = FLastRecBuf then // Dataset is empty (just opened)
  283. begin
  284. if getnextpacket = 0 then result := grEOF;
  285. end
  286. else if FCurrentRecBuf = nil then FCurrentRecBuf := FFirstRecBuf
  287. else if (PBufRecLinkItem(FCurrentRecBuf)^.next = FLastRecBuf) then
  288. begin
  289. if getnextpacket > 0 then
  290. begin
  291. FCurrentRecBuf := PBufRecLinkItem(FCurrentRecBuf)^.next;
  292. end
  293. else
  294. begin
  295. result:=grEOF;
  296. end
  297. end
  298. else
  299. begin
  300. FCurrentRecBuf := PBufRecLinkItem(FCurrentRecBuf)^.next;
  301. end;
  302. end;
  303. if Result = grOK then
  304. begin
  305. with PBufBookmark(Buffer + FRecordSize)^ do
  306. begin
  307. BookmarkData := FCurrentRecBuf;
  308. BookmarkFlag := bfCurrent;
  309. end;
  310. move((pointer(FCurrentRecBuf)+sizeof(TBufRecLinkItem))^,buffer^,FRecordSize);
  311. GetCalcFields(Buffer);
  312. if Filtered then
  313. begin
  314. FFilterBuffer := Buffer;
  315. SaveState := SetTempState(dsFilter);
  316. DoFilterRecord(Acceptable);
  317. if (GetMode = gmCurrent) and not Acceptable then
  318. begin
  319. Acceptable := True;
  320. Result := grError;
  321. end;
  322. RestoreState(SaveState);
  323. end;
  324. end
  325. else if (Result = grError) and doCheck then
  326. DatabaseError('No record');
  327. until Acceptable;
  328. end;
  329. function TBufDataset.GetRecordUpdateBuffer : boolean;
  330. var x : integer;
  331. CurrBuff : PChar;
  332. begin
  333. GetBookmarkData(ActiveBuffer,@CurrBuff);
  334. if (FCurrentUpdateBuffer >= length(FUpdateBuffer)) or (FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData <> CurrBuff) then
  335. for x := 0 to high(FUpdateBuffer) do
  336. if FUpdateBuffer[x].BookmarkData = CurrBuff then
  337. begin
  338. FCurrentUpdateBuffer := x;
  339. break;
  340. end;
  341. Result := (FCurrentUpdateBuffer < length(FUpdateBuffer)) and (FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData = CurrBuff);
  342. end;
  343. procedure TBufDataset.InternalSetToRecord(Buffer: PChar);
  344. begin
  345. FCurrentRecBuf := PBufBookmark(Buffer + FRecordSize)^.BookmarkData;
  346. end;
  347. procedure TBufDataset.SetBookmarkData(Buffer: PChar; Data: Pointer);
  348. begin
  349. PBufBookmark(Buffer + FRecordSize)^.BookmarkData := pointer(Data^);
  350. end;
  351. procedure TBufDataset.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
  352. begin
  353. PBufBookmark(Buffer + FRecordSize)^.BookmarkFlag := Value;
  354. end;
  355. procedure TBufDataset.GetBookmarkData(Buffer: PChar; Data: Pointer);
  356. begin
  357. pointer(Data^) := PBufBookmark(Buffer + FRecordSize)^.BookmarkData;
  358. end;
  359. function TBufDataset.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
  360. begin
  361. Result := PBufBookmark(Buffer + FRecordSize)^.BookmarkFlag;
  362. end;
  363. procedure TBufDataset.InternalGotoBookmark(ABookmark: Pointer);
  364. begin
  365. // note that ABookMark should be a PBufBookmark. But this way it can also be
  366. // a pointer to a TBufRecLinkItem
  367. FCurrentRecBuf := pointer(ABookmark^);
  368. end;
  369. function TBufDataset.getnextpacket : integer;
  370. var i : integer;
  371. pb : pchar;
  372. begin
  373. if FAllPacketsFetched then
  374. begin
  375. result := 0;
  376. exit;
  377. end;
  378. i := 0;
  379. pb := pchar(pointer(FLastRecBuf)+sizeof(TBufRecLinkItem));
  380. while ((i < FPacketRecords) or (FPacketRecords = -1)) and (loadbuffer(pb) = grOk) do
  381. begin
  382. FLastRecBuf^.next := pointer(IntAllocRecordBuffer);
  383. FLastRecBuf^.next^.prior := FLastRecBuf;
  384. FLastRecBuf := FLastRecBuf^.next;
  385. pb := pchar(pointer(FLastRecBuf)+sizeof(TBufRecLinkItem));
  386. inc(i);
  387. end;
  388. FBRecordCount := FBRecordCount + i;
  389. result := i;
  390. end;
  391. function TBufDataset.GetFieldSize(FieldDef : TFieldDef) : longint;
  392. begin
  393. case FieldDef.DataType of
  394. ftString,
  395. ftFixedChar: result := FieldDef.Size + 1;
  396. ftSmallint,
  397. ftInteger,
  398. ftword : result := sizeof(longint);
  399. ftBoolean : result := sizeof(wordbool);
  400. ftBCD : result := sizeof(currency);
  401. ftFloat : result := sizeof(double);
  402. ftLargeInt : result := sizeof(largeint);
  403. ftTime,
  404. ftDate,
  405. ftDateTime : result := sizeof(TDateTime);
  406. ftBlob : result := sizeof(TBufBlobField)
  407. else Result := 10
  408. end;
  409. end;
  410. function TBufDataset.LoadBuffer(Buffer : PChar): TGetResult;
  411. var NullMask : pbyte;
  412. x : longint;
  413. CreateblobField : boolean;
  414. BufBlob : PBufBlobField;
  415. begin
  416. if not Fetch then
  417. begin
  418. Result := grEOF;
  419. FAllPacketsFetched := True;
  420. Exit;
  421. end;
  422. NullMask := pointer(buffer);
  423. fillchar(Nullmask^,FNullmaskSize,0);
  424. inc(buffer,FNullmaskSize);
  425. for x := 0 to FieldDefs.count-1 do
  426. begin
  427. if not LoadField(FieldDefs[x],buffer,CreateblobField) then
  428. SetFieldIsNull(NullMask,x)
  429. else if CreateblobField then
  430. begin
  431. BufBlob := PBufBlobField(Buffer);
  432. BufBlob^.BlobBuffer := GetNewBlobBuffer;
  433. LoadBlobIntoBuffer(FieldDefs[x],BufBlob);
  434. end;
  435. inc(buffer,GetFieldSize(FieldDefs[x]));
  436. end;
  437. Result := grOK;
  438. end;
  439. function TBufDataset.GetCurrentBuffer: PChar;
  440. begin
  441. if State = dsFilter then Result := FFilterBuffer
  442. else if state = dsCalcFields then Result := CalcBuffer
  443. else Result := ActiveBuffer;
  444. end;
  445. function TBufDataset.GetFieldData(Field: TField; Buffer: Pointer;
  446. NativeFormat: Boolean): Boolean;
  447. begin
  448. Result := GetFieldData(Field, Buffer);
  449. end;
  450. function TBufDataset.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
  451. var CurrBuff : pchar;
  452. begin
  453. Result := False;
  454. if state = dsOldValue then
  455. begin
  456. if not GetRecordUpdateBuffer then
  457. begin
  458. // There is no old value available
  459. result := false;
  460. exit;
  461. end;
  462. currbuff := FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer+sizeof(TBufRecLinkItem);
  463. end
  464. else
  465. begin
  466. CurrBuff := GetCurrentBuffer;
  467. if not assigned(CurrBuff) then
  468. begin
  469. result := false;
  470. exit;
  471. end;
  472. end;
  473. If Field.Fieldno > 0 then // If = 0, then calculated field or something similar
  474. begin
  475. if GetFieldIsnull(pbyte(CurrBuff),Field.Fieldno-1) then
  476. begin
  477. result := false;
  478. exit;
  479. end;
  480. if assigned(buffer) then
  481. begin
  482. inc(CurrBuff,FFieldBufPositions[Field.FieldNo-1]);
  483. Move(CurrBuff^, Buffer^, GetFieldSize(FieldDefs[Field.FieldNo-1]));
  484. end;
  485. Result := True;
  486. end
  487. else
  488. begin
  489. Inc(CurrBuff, GetRecordSize + Field.Offset);
  490. Result := Boolean(CurrBuff^);
  491. if result and assigned(Buffer) then
  492. begin
  493. inc(CurrBuff);
  494. Move(CurrBuff^, Buffer^, Field.Datasize);
  495. end;
  496. end;
  497. end;
  498. procedure TBufDataset.SetFieldData(Field: TField; Buffer: Pointer;
  499. NativeFormat: Boolean);
  500. begin
  501. SetFieldData(Field,Buffer);
  502. end;
  503. procedure TBufDataset.SetFieldData(Field: TField; Buffer: Pointer);
  504. var CurrBuff : pointer;
  505. NullMask : pbyte;
  506. begin
  507. if not (state in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then
  508. begin
  509. DatabaseErrorFmt(SNotInEditState,[Name],self);
  510. exit;
  511. end;
  512. if state = dsFilter then // Set the value into the 'temporary' FLastRecBuf buffer for Locate and Lookup
  513. CurrBuff := pointer(FLastRecBuf) + sizeof(TBufRecLinkItem)
  514. else
  515. CurrBuff := GetCurrentBuffer;
  516. If Field.Fieldno > 0 then // If = 0, then calculated field or something
  517. begin
  518. NullMask := CurrBuff;
  519. inc(CurrBuff,FFieldBufPositions[Field.FieldNo-1]);
  520. if assigned(buffer) then
  521. begin
  522. Move(Buffer^, CurrBuff^, GetFieldSize(FieldDefs[Field.FieldNo-1]));
  523. unSetFieldIsNull(NullMask,Field.FieldNo-1);
  524. end
  525. else
  526. SetFieldIsNull(NullMask,Field.FieldNo-1);
  527. end
  528. else
  529. begin
  530. Inc(CurrBuff, GetRecordSize + Field.Offset);
  531. Boolean(CurrBuff^) := Buffer <> nil;
  532. inc(CurrBuff);
  533. if assigned(Buffer) then
  534. Move(Buffer^, CurrBuff^, Field.Datasize);
  535. end;
  536. if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
  537. DataEvent(deFieldChange, Ptrint(Field));
  538. end;
  539. procedure TBufDataset.InternalDelete;
  540. begin
  541. GetBookmarkData(ActiveBuffer,@FCurrentRecBuf);
  542. if FCurrentRecBuf <> FFirstRecBuf then FCurrentRecBuf^.prior^.next := FCurrentRecBuf^.next
  543. else FFirstRecBuf := FCurrentRecBuf^.next;
  544. FCurrentRecBuf^.next^.prior := FCurrentRecBuf^.prior;
  545. if not GetRecordUpdateBuffer then
  546. begin
  547. FCurrentUpdateBuffer := length(FUpdateBuffer);
  548. SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
  549. FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := pchar(FCurrentRecBuf);
  550. FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FCurrentRecBuf;
  551. FCurrentRecBuf := FCurrentRecBuf^.next;
  552. end
  553. else
  554. begin
  555. if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind = ukModify then
  556. begin
  557. FCurrentRecBuf := FCurrentRecBuf^.next;
  558. FreeRecordBuffer(pchar(FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData));
  559. FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer;
  560. end
  561. else
  562. begin
  563. FCurrentRecBuf := FCurrentRecBuf^.next;
  564. FreeRecordBuffer(pchar(FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData));
  565. FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := nil; //this 'disables' the updatebuffer
  566. end;
  567. end;
  568. dec(FBRecordCount);
  569. FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukDelete;
  570. end;
  571. procedure TBufDataset.ApplyRecUpdate(UpdateKind : TUpdateKind);
  572. begin
  573. raise EDatabaseError.Create(SApplyRecNotSupported);
  574. end;
  575. procedure TBufDataset.CancelUpdates;
  576. var r : Integer;
  577. begin
  578. CheckBrowseMode;
  579. if Length(FUpdateBuffer) > 0 then
  580. begin
  581. r := Length(FUpdateBuffer) -1;
  582. while r > -1 do with FUpdateBuffer[r] do
  583. begin
  584. if assigned(FUpdateBuffer[r].BookmarkData) then
  585. begin
  586. if UpdateKind = ukModify then
  587. begin
  588. move(pchar(OldValuesBuffer+sizeof(TBufRecLinkItem))^,pchar(BookmarkData+sizeof(TBufRecLinkItem))^,FRecordSize);
  589. FreeRecordBuffer(OldValuesBuffer);
  590. end
  591. else if UpdateKind = ukDelete then
  592. begin
  593. if assigned(PBufRecLinkItem(BookmarkData)^.prior) then // or else it was the first record
  594. PBufRecLinkItem(BookmarkData)^.prior^.next := BookmarkData
  595. else
  596. FFirstRecBuf := BookmarkData;
  597. PBufRecLinkItem(BookmarkData)^.next^.prior := BookmarkData;
  598. inc(FBRecordCount);
  599. end
  600. else if UpdateKind = ukInsert then
  601. begin
  602. if assigned(PBufRecLinkItem(BookmarkData)^.prior) then // or else it was the first record
  603. PBufRecLinkItem(BookmarkData)^.prior^.next := PBufRecLinkItem(BookmarkData)^.next
  604. else
  605. FFirstRecBuf := PBufRecLinkItem(BookmarkData)^.next;
  606. PBufRecLinkItem(BookmarkData)^.next^.prior := PBufRecLinkItem(BookmarkData)^.prior;
  607. // resync won't work if the currentbuffer is freed...
  608. if FCurrentRecBuf = BookmarkData then FCurrentRecBuf := FCurrentRecBuf^.next;
  609. FreeRecordBuffer(BookmarkData);
  610. dec(FBRecordCount);
  611. end;
  612. end;
  613. dec(r)
  614. end;
  615. SetLength(FUpdateBuffer,0);
  616. Resync([]);
  617. end;
  618. end;
  619. procedure TBufDataset.SetOnUpdateError(const AValue: TResolverErrorEvent);
  620. begin
  621. FOnUpdateError := AValue;
  622. end;
  623. procedure TBufDataset.ApplyUpdates; // For backwards-compatibility
  624. begin
  625. ApplyUpdates(0);
  626. end;
  627. procedure TBufDataset.ApplyUpdates(MaxErrors: Integer);
  628. var r : Integer;
  629. FailedCount : integer;
  630. Response : TResolverResponse;
  631. StoreRecBuf : PBufRecLinkItem;
  632. AUpdateErr : EUpdateError;
  633. begin
  634. CheckBrowseMode;
  635. StoreRecBuf := FCurrentRecBuf;
  636. r := 0;
  637. FailedCount := 0;
  638. Response := rrApply;
  639. try
  640. while (r < Length(FUpdateBuffer)) and (Response <> rrAbort) do
  641. begin
  642. if assigned(FUpdateBuffer[r].BookmarkData) then
  643. begin
  644. InternalGotoBookmark(@FUpdateBuffer[r].BookmarkData);
  645. Resync([rmExact,rmCenter]);
  646. Response := rrApply;
  647. try
  648. ApplyRecUpdate(FUpdateBuffer[r].UpdateKind);
  649. except
  650. on E: EDatabaseError do
  651. begin
  652. Inc(FailedCount);
  653. if failedcount > word(MaxErrors) then Response := rrAbort
  654. else Response := rrSkip;
  655. if assigned(FOnUpdateError) then
  656. begin
  657. AUpdateErr := EUpdateError.Create(SOnUpdateError,E.Message,0,0,Exception(AcquireExceptionObject));
  658. FOnUpdateError(Self,Self,AUpdateErr,FUpdateBuffer[r].UpdateKind,Response);
  659. AUpdateErr.Free;
  660. if Response in [rrApply, rrIgnore] then dec(FailedCount);
  661. if Response = rrApply then dec(r);
  662. end
  663. else if Response = rrAbort then
  664. Raise EUpdateError.Create(SOnUpdateError,E.Message,0,0,Exception(AcquireExceptionObject));
  665. end
  666. else
  667. raise;
  668. end;
  669. if response in [rrApply, rrIgnore] then
  670. begin
  671. FreeRecordBuffer(FUpdateBuffer[r].OldValuesBuffer);
  672. FUpdateBuffer[r].BookmarkData := nil;
  673. end
  674. end;
  675. inc(r);
  676. end;
  677. finally
  678. if failedcount = 0 then
  679. begin
  680. SetLength(FUpdateBuffer,0);
  681. if assigned(FUpdateBlobBuffers) then for r:=0 to length(FUpdateBlobBuffers)-1 do
  682. if assigned(FUpdateBlobBuffers[r]) then
  683. begin
  684. if FUpdateBlobBuffers[r]^.OrgBufID >= 0 then
  685. begin
  686. Freemem(FBlobBuffers[FUpdateBlobBuffers[r]^.OrgBufID]^.Buffer);
  687. Dispose(FBlobBuffers[FUpdateBlobBuffers[r]^.OrgBufID]);
  688. FBlobBuffers[FUpdateBlobBuffers[r]^.OrgBufID] :=FUpdateBlobBuffers[r];
  689. end
  690. else
  691. begin
  692. setlength(FBlobBuffers,length(FBlobBuffers)+1);
  693. FUpdateBlobBuffers[r]^.OrgBufID := high(FBlobBuffers);
  694. FBlobBuffers[high(FBlobBuffers)] := FUpdateBlobBuffers[r];
  695. end;
  696. end;
  697. SetLength(FUpdateBlobBuffers,0);
  698. end;
  699. FCurrentRecBuf := StoreRecBuf;
  700. Resync([]);
  701. end;
  702. end;
  703. procedure TBufDataset.InternalCancel;
  704. Var i : integer;
  705. begin
  706. if assigned(FUpdateBlobBuffers) then for i:=0 to length(FUpdateBlobBuffers)-1 do
  707. if assigned(FUpdateBlobBuffers[i]) and (FUpdateBlobBuffers[i]^.FieldNo>0) then
  708. begin
  709. Reallocmem(FUpdateBlobBuffers[i]^.Buffer,0);
  710. Dispose(FUpdateBlobBuffers[i]);
  711. FUpdateBlobBuffers[i] := nil;
  712. end;
  713. end;
  714. procedure TBufDataset.InternalPost;
  715. Var tmpRecBuffer : PBufRecLinkItem;
  716. CurrBuff : PChar;
  717. i : integer;
  718. blobbuf : tbufblobfield;
  719. NullMask : pbyte;
  720. begin
  721. if assigned(FUpdateBlobBuffers) then for i:=0 to length(FUpdateBlobBuffers)-1 do
  722. if assigned(FUpdateBlobBuffers[i]) and (FUpdateBlobBuffers[i]^.FieldNo>0) then
  723. begin
  724. blobbuf.BlobBuffer := FUpdateBlobBuffers[i];
  725. CurrBuff := ActiveBuffer;
  726. NullMask := pbyte(CurrBuff);
  727. inc(CurrBuff,FFieldBufPositions[FUpdateBlobBuffers[i]^.FieldNo-1]);
  728. Move(blobbuf, CurrBuff^, GetFieldSize(FieldDefs[FUpdateBlobBuffers[i]^.FieldNo-1]));
  729. unSetFieldIsNull(NullMask,FUpdateBlobBuffers[i]^.FieldNo-1);
  730. FUpdateBlobBuffers[i]^.FieldNo := -1;
  731. end;
  732. if state = dsInsert then
  733. begin
  734. if GetBookmarkFlag(ActiveBuffer) = bfEOF then
  735. // Append
  736. FCurrentRecBuf := FLastRecBuf
  737. else
  738. // The active buffer is the newly created TDataset record,
  739. // from which the bookmark is set to the record where the new record should be
  740. // inserted
  741. GetBookmarkData(ActiveBuffer,@FCurrentRecBuf);
  742. // Create the new record buffer
  743. tmpRecBuffer := FCurrentRecBuf^.prior;
  744. FCurrentRecBuf^.prior := pointer(IntAllocRecordBuffer);
  745. FCurrentRecBuf^.prior^.next := FCurrentRecBuf;
  746. FCurrentRecBuf := FCurrentRecBuf^.prior;
  747. If assigned(tmpRecBuffer) then // if not, it's the first record
  748. begin
  749. FCurrentRecBuf^.prior := tmpRecBuffer;
  750. tmpRecBuffer^.next := FCurrentRecBuf
  751. end
  752. else
  753. FFirstRecBuf := FCurrentRecBuf;
  754. // Link the newly created record buffer to the newly created TDataset record
  755. with PBufBookmark(ActiveBuffer + FRecordSize)^ do
  756. begin
  757. BookmarkData := FCurrentRecBuf;
  758. BookmarkFlag := bfInserted;
  759. end;
  760. inc(FBRecordCount);
  761. end
  762. else
  763. GetBookmarkData(ActiveBuffer,@FCurrentRecBuf);
  764. if not GetRecordUpdateBuffer then
  765. begin
  766. FCurrentUpdateBuffer := length(FUpdateBuffer);
  767. SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
  768. FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := FCurrentRecBuf;
  769. if state = dsEdit then
  770. begin
  771. // Update the oldvalues-buffer
  772. FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := intAllocRecordBuffer;
  773. move(FCurrentRecBuf^,FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize+sizeof(TBufRecLinkItem));
  774. FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukModify;
  775. end
  776. else
  777. FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukInsert;
  778. end;
  779. CurrBuff := pchar(FCurrentRecBuf);
  780. inc(Currbuff,sizeof(TBufRecLinkItem));
  781. move(ActiveBuffer^,CurrBuff^,FRecordSize);
  782. end;
  783. procedure TBufDataset.CalcRecordSize;
  784. var x : longint;
  785. begin
  786. FNullmaskSize := 1+((FieldDefs.count-1) div 8);
  787. FRecordSize := FNullmaskSize;
  788. SetLength(FFieldBufPositions,FieldDefs.count);
  789. for x := 0 to FieldDefs.count-1 do
  790. begin
  791. FFieldBufPositions[x] := FRecordSize;
  792. inc(FRecordSize, GetFieldSize(FieldDefs[x]));
  793. end;
  794. end;
  795. function TBufDataset.GetRecordSize : Word;
  796. begin
  797. result := FRecordSize + sizeof(TBufBookmark);
  798. end;
  799. function TBufDataset.GetChangeCount: integer;
  800. begin
  801. result := length(FUpdateBuffer);
  802. end;
  803. procedure TBufDataset.InternalInitRecord(Buffer: PChar);
  804. begin
  805. FillChar(Buffer^, FRecordSize, #0);
  806. fillchar(Buffer^,FNullmaskSize,255);
  807. end;
  808. procedure TBufDataset.SetRecNo(Value: Longint);
  809. var recnr : integer;
  810. TmpRecBuffer : PBufRecLinkItem;
  811. begin
  812. checkbrowsemode;
  813. if value > RecordCount then
  814. begin
  815. repeat until (getnextpacket < FPacketRecords) or (value <= RecordCount) or (FPacketRecords = -1);
  816. if value > RecordCount then
  817. begin
  818. DatabaseError(SNoSuchRecord,self);
  819. exit;
  820. end;
  821. end;
  822. TmpRecBuffer := FFirstRecBuf;
  823. for recnr := 1 to value-1 do
  824. TmpRecBuffer := TmpRecBuffer^.next;
  825. GotoBookmark(@TmpRecBuffer);
  826. end;
  827. function TBufDataset.GetRecNo: Longint;
  828. Var SearchRecBuffer : PBufRecLinkItem;
  829. TmpRecBuffer : PBufRecLinkItem;
  830. recnr : integer;
  831. abuf : PChar;
  832. begin
  833. abuf := GetCurrentBuffer;
  834. // If abuf isn't assigned, the recordset probably isn't opened.
  835. if assigned(abuf) and (FBRecordCount>0) and (state <> dsInsert) then
  836. begin
  837. GetBookmarkData(abuf,@SearchRecBuffer);
  838. TmpRecBuffer := FFirstRecBuf;
  839. recnr := 1;
  840. while TmpRecBuffer <> SearchRecBuffer do
  841. begin
  842. inc(recnr);
  843. TmpRecBuffer := TmpRecBuffer^.next;
  844. end;
  845. result := recnr;
  846. end
  847. else result := 0;
  848. end;
  849. function TBufDataset.IsCursorOpen: Boolean;
  850. begin
  851. Result := FOpen;
  852. end;
  853. Function TBufDataset.GetRecordCount: Longint;
  854. begin
  855. Result := FBRecordCount;
  856. end;
  857. Function TBufDataSet.UpdateStatus: TUpdateStatus;
  858. begin
  859. Result:=usUnmodified;
  860. if GetRecordUpdateBuffer then
  861. case FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind of
  862. ukModify : Result := usModified;
  863. ukInsert : Result := usInserted;
  864. ukDelete : Result := usDeleted;
  865. end;
  866. end;
  867. function TbufDataset.GetNewBlobBuffer : PBlobBuffer;
  868. var ABlobBuffer : PBlobBuffer;
  869. begin
  870. setlength(FBlobBuffers,length(FBlobBuffers)+1);
  871. new(ABlobBuffer);
  872. fillbyte(ABlobBuffer^,sizeof(ABlobBuffer^),0);
  873. ABlobBuffer^.OrgBufID := high(FUpdateBlobBuffers);
  874. FBlobBuffers[high(FBlobBuffers)] := ABlobBuffer;
  875. result := ABlobBuffer;
  876. end;
  877. function TbufDataset.GetNewWriteBlobBuffer : PBlobBuffer;
  878. var ABlobBuffer : PBlobBuffer;
  879. begin
  880. setlength(FUpdateBlobBuffers,length(FUpdateBlobBuffers)+1);
  881. new(ABlobBuffer);
  882. fillbyte(ABlobBuffer^,sizeof(ABlobBuffer^),0);
  883. FUpdateBlobBuffers[high(FUpdateBlobBuffers)] := ABlobBuffer;
  884. result := ABlobBuffer;
  885. end;
  886. function TBufBlobStream.Seek(Offset: Longint; Origin: Word): Longint;
  887. begin
  888. Case Origin of
  889. soFromBeginning : FPosition:=Offset;
  890. soFromEnd : FPosition:=FBlobBuffer^.Size+Offset;
  891. soFromCurrent : FpoSition:=FPosition+Offset;
  892. end;
  893. Result:=FPosition;
  894. end;
  895. function TBufBlobStream.Read(var Buffer; Count: Longint): Longint;
  896. var ptr : pointer;
  897. begin
  898. if FPosition + count > FBlobBuffer^.Size then
  899. count := FBlobBuffer^.Size-FPosition;
  900. ptr := FBlobBuffer^.Buffer+FPosition;
  901. move(ptr^,buffer,count);
  902. inc(FPosition,count);
  903. result := count;
  904. end;
  905. function TBufBlobStream.Write(const Buffer; Count: Longint): Longint;
  906. var ptr : pointer;
  907. begin
  908. ReAllocMem(FBlobBuffer^.Buffer,FPosition+Count);
  909. ptr := FBlobBuffer^.Buffer+FPosition;
  910. move(buffer,ptr^,count);
  911. inc(FBlobBuffer^.Size,count);
  912. inc(FPosition,count);
  913. Result := count;
  914. end;
  915. constructor TBufBlobStream.Create(Field: TBlobField; Mode: TBlobStreamMode);
  916. var bufblob : TBufBlobField;
  917. begin
  918. FDataset := Field.DataSet as TBufDataset;
  919. if mode = bmread then
  920. begin
  921. if not field.getData(@bufblob) then
  922. DatabaseError(SFieldIsNull);
  923. if not assigned(bufblob.BlobBuffer) then with FDataSet do
  924. begin
  925. FBlobBuffer := GetNewBlobBuffer;
  926. bufblob.BlobBuffer := FBlobBuffer;
  927. LoadBlobIntoBuffer(FieldDefs[field.FieldNo-1],@bufblob);
  928. end
  929. else
  930. FBlobBuffer := bufblob.BlobBuffer;
  931. end
  932. else if mode=bmWrite then with FDataSet as TBufDataset do
  933. begin
  934. FBlobBuffer := GetNewWriteBlobBuffer;
  935. FBlobBuffer^.FieldNo := Field.FieldNo;
  936. if (field.getData(@bufblob)) and assigned(bufblob.BlobBuffer) then
  937. FBlobBuffer^.OrgBufID := bufblob.BlobBuffer^.OrgBufID
  938. else
  939. FBlobBuffer^.OrgBufID := -1;
  940. end;
  941. end;
  942. function TBufDataset.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
  943. var bufblob : TBufBlobField;
  944. begin
  945. result := nil;
  946. if mode=bmread then
  947. begin
  948. if not field.getData(@bufblob) then
  949. exit;
  950. result := TBufBlobStream.Create(Field as tblobfield,bmread);
  951. end
  952. else if mode=bmWrite then
  953. begin
  954. if not (state in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then
  955. begin
  956. DatabaseErrorFmt(SNotInEditState,[Name],self);
  957. exit;
  958. end;
  959. result := TBufBlobStream.Create(Field as tblobfield,bmWrite);
  960. if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
  961. DataEvent(deFieldChange, Ptrint(Field));
  962. end;
  963. end;
  964. procedure TBufDataset.DoFilterRecord(var Acceptable: Boolean);
  965. begin
  966. Acceptable := true;
  967. // check user filter
  968. if Assigned(OnFilterRecord) then
  969. OnFilterRecord(Self, Acceptable);
  970. // check filtertext
  971. if Acceptable and (Length(Filter) > 0) then
  972. Acceptable := Boolean((FParser.ExtractFromBuffer(GetCurrentBuffer))^);
  973. end;
  974. procedure TBufDataset.SetFilterText(const Value: String);
  975. begin
  976. if Value = Filter then
  977. exit;
  978. // parse
  979. ParseFilter(Value);
  980. // call dataset method
  981. inherited;
  982. // refilter dataset if filtered
  983. if IsCursorOpen and Filtered then Refresh;
  984. end;
  985. procedure TBufDataset.SetFiltered(Value: Boolean); {override;}
  986. begin
  987. if Value = Filtered then
  988. exit;
  989. // pass on to ancestor
  990. inherited;
  991. // only refresh if active
  992. if IsCursorOpen then
  993. Refresh;
  994. end;
  995. procedure TBufDataset.ParseFilter(const AFilter: string);
  996. begin
  997. // parser created?
  998. if Length(AFilter) > 0 then
  999. begin
  1000. if (FParser = nil) and IsCursorOpen then
  1001. begin
  1002. FParser := TBufDatasetParser.Create(Self);
  1003. end;
  1004. // have a parser now?
  1005. if FParser <> nil then
  1006. begin
  1007. // set options
  1008. FParser.PartialMatch := not (foNoPartialCompare in FilterOptions);
  1009. FParser.CaseInsensitive := foCaseInsensitive in FilterOptions;
  1010. // parse expression
  1011. FParser.ParseExpression(AFilter);
  1012. end;
  1013. end;
  1014. end;
  1015. Function TBufDataset.Locate(const KeyFields: string; const KeyValues: Variant; options: TLocateOptions) : boolean;
  1016. function CompareText0(substr, astr: pchar; len : integer; options: TLocateOptions): integer;
  1017. var
  1018. i : integer; Chr1, Chr2: byte;
  1019. begin
  1020. result := 0;
  1021. i := 0;
  1022. chr1 := 1;
  1023. while (result=0) and (i<len) and (chr1 <> 0) do
  1024. begin
  1025. Chr1 := byte(substr[i]);
  1026. Chr2 := byte(astr[i]);
  1027. inc(i);
  1028. if loCaseInsensitive in options then
  1029. begin
  1030. if Chr1 in [97..122] then
  1031. dec(Chr1,32);
  1032. if Chr2 in [97..122] then
  1033. dec(Chr2,32);
  1034. end;
  1035. result := Chr1 - Chr2;
  1036. end;
  1037. if (result <> 0) and (chr1 = 0) and (loPartialKey in options) then result := 0;
  1038. end;
  1039. var keyfield : TField; // Field to search in
  1040. ValueBuffer : pchar; // Pointer to value to search for, in TField' internal format
  1041. VBLength : integer;
  1042. FieldBufPos : PtrInt; // Amount to add to the record buffer to get the FieldBuffer
  1043. CurrLinkItem: PBufRecLinkItem;
  1044. CurrBuff : pchar;
  1045. bm : TBufBookmark;
  1046. CheckNull : Boolean;
  1047. SaveState : TDataSetState;
  1048. begin
  1049. // For now it is only possible to search in one field at the same time
  1050. result := False;
  1051. if IsEmpty then exit;
  1052. keyfield := FieldByName(keyfields);
  1053. CheckNull := VarIsNull(KeyValues);
  1054. if not CheckNull then
  1055. begin
  1056. SaveState := State;
  1057. SetTempState(dsFilter);
  1058. keyfield.Value := KeyValues;
  1059. RestoreState(SaveState);
  1060. FieldBufPos := FFieldBufPositions[keyfield.FieldNo-1];
  1061. VBLength := keyfield.DataSize;
  1062. ValueBuffer := AllocMem(VBLength);
  1063. currbuff := pointer(FLastRecBuf)+sizeof(TBufRecLinkItem)+FieldBufPos;
  1064. move(currbuff^,ValueBuffer^,VBLength);
  1065. end;
  1066. CurrLinkItem := FFirstRecBuf;
  1067. if CheckNull then
  1068. begin
  1069. repeat
  1070. currbuff := pointer(CurrLinkItem)+sizeof(TBufRecLinkItem);
  1071. if GetFieldIsnull(pbyte(CurrBuff),keyfield.Fieldno-1) then
  1072. begin
  1073. result := True;
  1074. break;
  1075. end;
  1076. CurrLinkItem := CurrLinkItem^.next;
  1077. if CurrLinkItem = FLastRecBuf then getnextpacket;
  1078. until CurrLinkItem = FLastRecBuf;
  1079. end
  1080. else if keyfield.DataType = ftString then
  1081. begin
  1082. repeat
  1083. currbuff := pointer(CurrLinkItem)+sizeof(TBufRecLinkItem);
  1084. if not GetFieldIsnull(pbyte(CurrBuff),keyfield.Fieldno-1) then
  1085. begin
  1086. inc(CurrBuff,FieldBufPos);
  1087. if CompareText0(ValueBuffer,CurrBuff,VBLength,options) = 0 then
  1088. begin
  1089. result := True;
  1090. break;
  1091. end;
  1092. end;
  1093. CurrLinkItem := CurrLinkItem^.next;
  1094. if CurrLinkItem = FLastRecBuf then getnextpacket;
  1095. until CurrLinkItem = FLastRecBuf;
  1096. end
  1097. else
  1098. begin
  1099. repeat
  1100. currbuff := pointer(CurrLinkItem)+sizeof(TBufRecLinkItem);
  1101. if not GetFieldIsnull(pbyte(CurrBuff),keyfield.Fieldno-1) then
  1102. begin
  1103. inc(CurrBuff,FieldBufPos);
  1104. if CompareByte(ValueBuffer^,CurrBuff^,VBLength) = 0 then
  1105. begin
  1106. result := True;
  1107. break;
  1108. end;
  1109. end;
  1110. CurrLinkItem := CurrLinkItem^.next;
  1111. if CurrLinkItem = FLastRecBuf then getnextpacket;
  1112. until CurrLinkItem = FLastRecBuf;
  1113. end;
  1114. if Result then
  1115. begin
  1116. bm.BookmarkData := CurrLinkItem;
  1117. bm.BookmarkFlag := bfCurrent;
  1118. GotoBookmark(@bm);
  1119. end;
  1120. ReAllocmem(ValueBuffer,0);
  1121. end;
  1122. begin
  1123. end.