bufdataset.pas 107 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608
  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. TCustomBufDataset = Class;
  19. TResolverErrorEvent = procedure(Sender: TObject; DataSet: TCustomBufDataset; 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 : TCustomBufDataset;
  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. { TCustomBufDataset }
  42. PBufRecLinkItem = ^TBufRecLinkItem;
  43. TBufRecLinkItem = record
  44. prior : PBufRecLinkItem;
  45. next : PBufRecLinkItem;
  46. end;
  47. PBufBookmark = ^TBufBookmark;
  48. TBufBookmark = record
  49. BookmarkData : PBufRecLinkItem;
  50. BookmarkInt : integer;
  51. BookmarkFlag : TBookmarkFlag;
  52. end;
  53. TRecUpdateBuffer = record
  54. UpdateKind : TUpdateKind;
  55. { BookMarkData:
  56. - Is -1 if the update has canceled out. For example: a appended record has been deleted again
  57. - If UpdateKind is ukInsert it contains a bookmark to the new created record
  58. - If UpdateKind is ukModify it contains a bookmark to the record with the new data
  59. - If UpdateKind is ukDelete it contains a bookmark to the deleted record (ie: the record is still there)
  60. }
  61. BookmarkData : TBufBookmark;
  62. { NextBookMarkData:
  63. - If UpdateKind is ukDelete it contains a bookmark to the record just after the deleted record
  64. }
  65. NextBookmarkData : TBufBookmark;
  66. { OldValuesBuffer:
  67. - If UpdateKind is ukModify it contains a record-buffer which contains the old data
  68. - If UpdateKind is ukDelete it contains a record-buffer with the data of the deleted record
  69. }
  70. OldValuesBuffer : TRecordBuffer;
  71. end;
  72. TRecordsUpdateBuffer = array of TRecUpdateBuffer;
  73. PBufBlobField = ^TBufBlobField;
  74. TBufBlobField = record
  75. ConnBlobBuffer : array[0..11] of byte; // It's here where the db-specific data is stored
  76. BlobBuffer : PBlobBuffer;
  77. end;
  78. TCompareFunc = function(subValue, aValue: pointer; options: TLocateOptions): int64;
  79. TDBCompareRec = record
  80. Comparefunc : TCompareFunc;
  81. Off1,Off2 : PtrInt;
  82. FieldInd1,
  83. FieldInd2 : longint;
  84. NullBOff1,
  85. NullBOff2 : PtrInt;
  86. Options : TLocateOptions;
  87. Desc : Boolean;
  88. end;
  89. TDBCompareStruct = array of TDBCompareRec;
  90. { TBufIndex }
  91. TBufIndex = class(TObject)
  92. private
  93. FDataset : TCustomBufDataset;
  94. protected
  95. function GetBookmarkSize: integer; virtual; abstract;
  96. function GetCurrentBuffer: Pointer; virtual; abstract;
  97. function GetCurrentRecord: TRecordBuffer; virtual; abstract;
  98. function GetIsInitialized: boolean; virtual; abstract;
  99. function GetSpareBuffer: TRecordBuffer; virtual; abstract;
  100. function GetSpareRecord: TRecordBuffer; virtual; abstract;
  101. public
  102. DBCompareStruct : TDBCompareStruct;
  103. Name : String;
  104. FieldsName : String;
  105. CaseinsFields : String;
  106. DescFields : String;
  107. Options : TIndexOptions;
  108. IndNr : integer;
  109. constructor Create(const ADataset : TCustomBufDataset); virtual;
  110. function ScrollBackward : TGetResult; virtual; abstract;
  111. function ScrollForward : TGetResult; virtual; abstract;
  112. function GetCurrent : TGetResult; virtual; abstract;
  113. function ScrollFirst : TGetResult; virtual; abstract;
  114. procedure ScrollLast; virtual; abstract;
  115. procedure SetToFirstRecord; virtual; abstract;
  116. procedure SetToLastRecord; virtual; abstract;
  117. procedure StoreCurrentRecord; virtual; abstract;
  118. procedure RestoreCurrentRecord; virtual; abstract;
  119. function CanScrollForward : Boolean; virtual; abstract;
  120. procedure DoScrollForward; virtual; abstract;
  121. procedure StoreCurrentRecIntoBookmark(const ABookmark: PBufBookmark); virtual; abstract;
  122. procedure StoreSpareRecIntoBookmark(const ABookmark: PBufBookmark); virtual; abstract;
  123. procedure GotoBookmark(const ABookmark : PBufBookmark); virtual; abstract;
  124. function BookmarkValid(const ABookmark: PBufBookmark): boolean; virtual;
  125. procedure InitialiseIndex; virtual; abstract;
  126. procedure InitialiseSpareRecord(const ASpareRecord : TRecordBuffer); virtual; abstract;
  127. procedure ReleaseSpareRecord; virtual; abstract;
  128. procedure BeginUpdate; virtual; abstract;
  129. // Adds a record to the end of the index as the new last record (spare record)
  130. // Normally only used in GetNextPacket
  131. procedure AddRecord; virtual; abstract;
  132. // Inserts a record before the current record, or if the record is sorted,
  133. // insert it to the proper position
  134. procedure InsertRecordBeforeCurrentRecord(Const ARecord : TRecordBuffer); virtual; abstract;
  135. procedure EndUpdate; virtual; abstract;
  136. procedure RemoveRecordFromIndex(const ABookmark : TBufBookmark); virtual; abstract;
  137. function CompareBookmarks(const ABookmark1, ABookmark2 : PBufBookmark) : boolean; virtual;
  138. Function GetRecNo(const ABookmark : PBufBookmark) : integer; virtual; abstract;
  139. property SpareRecord : TRecordBuffer read GetSpareRecord;
  140. property SpareBuffer : TRecordBuffer read GetSpareBuffer;
  141. property CurrentRecord : TRecordBuffer read GetCurrentRecord;
  142. property CurrentBuffer : Pointer read GetCurrentBuffer;
  143. property IsInitialized : boolean read GetIsInitialized;
  144. property BookmarkSize : integer read GetBookmarkSize;
  145. end;
  146. TDataPacketFormat = (dfBinary,dfXML,dfXMLUTF8,dfAny);
  147. { TDoubleLinkedBufIndex }
  148. TDoubleLinkedBufIndex = class(TBufIndex)
  149. private
  150. FCursOnFirstRec : boolean;
  151. FStoredRecBuf : PBufRecLinkItem;
  152. FCurrentRecBuf : PBufRecLinkItem;
  153. protected
  154. function GetBookmarkSize: integer; override;
  155. function GetCurrentBuffer: Pointer; override;
  156. function GetCurrentRecord: TRecordBuffer; override;
  157. function GetIsInitialized: boolean; override;
  158. function GetSpareBuffer: TRecordBuffer; override;
  159. function GetSpareRecord: TRecordBuffer; override;
  160. public
  161. FLastRecBuf : PBufRecLinkItem;
  162. FFirstRecBuf : PBufRecLinkItem;
  163. FNeedScroll : Boolean;
  164. function ScrollBackward : TGetResult; override;
  165. function ScrollForward : TGetResult; override;
  166. function GetCurrent : TGetResult; override;
  167. function ScrollFirst : TGetResult; override;
  168. procedure ScrollLast; override;
  169. procedure SetToFirstRecord; override;
  170. procedure SetToLastRecord; override;
  171. procedure StoreCurrentRecord; override;
  172. procedure RestoreCurrentRecord; override;
  173. function CanScrollForward : Boolean; override;
  174. procedure DoScrollForward; override;
  175. procedure StoreCurrentRecIntoBookmark(const ABookmark: PBufBookmark); override;
  176. procedure StoreSpareRecIntoBookmark(const ABookmark: PBufBookmark); override;
  177. procedure GotoBookmark(const ABookmark : PBufBookmark); override;
  178. procedure InitialiseIndex; override;
  179. procedure InitialiseSpareRecord(const ASpareRecord : TRecordBuffer); override;
  180. procedure ReleaseSpareRecord; override;
  181. procedure RemoveRecordFromIndex(const ABookmark : TBufBookmark); override;
  182. Function GetRecNo(const ABookmark : PBufBookmark) : integer; override;
  183. procedure BeginUpdate; override;
  184. procedure AddRecord; override;
  185. procedure InsertRecordBeforeCurrentRecord(Const ARecord : TRecordBuffer); override;
  186. procedure EndUpdate; override;
  187. end;
  188. { TUniDirectionalBufIndex }
  189. TUniDirectionalBufIndex = class(TBufIndex)
  190. private
  191. FSPareBuffer: TRecordBuffer;
  192. protected
  193. function GetBookmarkSize: integer; override;
  194. function GetCurrentBuffer: Pointer; override;
  195. function GetCurrentRecord: TRecordBuffer; override;
  196. function GetIsInitialized: boolean; override;
  197. function GetSpareBuffer: TRecordBuffer; override;
  198. function GetSpareRecord: TRecordBuffer; override;
  199. public
  200. function ScrollBackward : TGetResult; override;
  201. function ScrollForward : TGetResult; override;
  202. function GetCurrent : TGetResult; override;
  203. function ScrollFirst : TGetResult; override;
  204. procedure ScrollLast; override;
  205. procedure SetToFirstRecord; override;
  206. procedure SetToLastRecord; override;
  207. procedure StoreCurrentRecord; override;
  208. procedure RestoreCurrentRecord; override;
  209. function CanScrollForward : Boolean; override;
  210. procedure DoScrollForward; override;
  211. procedure StoreCurrentRecIntoBookmark(const ABookmark: PBufBookmark); override;
  212. procedure StoreSpareRecIntoBookmark(const ABookmark: PBufBookmark); override;
  213. procedure GotoBookmark(const ABookmark : PBufBookmark); override;
  214. procedure InitialiseIndex; override;
  215. procedure InitialiseSpareRecord(const ASpareRecord : TRecordBuffer); override;
  216. procedure ReleaseSpareRecord; override;
  217. procedure RemoveRecordFromIndex(const ABookmark : TBufBookmark); override;
  218. Function GetRecNo(const ABookmark : PBufBookmark) : integer; override;
  219. procedure BeginUpdate; override;
  220. procedure AddRecord; override;
  221. procedure InsertRecordBeforeCurrentRecord(Const ARecord : TRecordBuffer); override;
  222. procedure EndUpdate; override;
  223. end;
  224. { TArrayBufIndex }
  225. TArrayBufIndex = class(TBufIndex)
  226. private
  227. FStoredRecBuf : integer;
  228. FInitialBuffers,
  229. FGrowBuffer : integer;
  230. Function GetRecordFromBookmark(ABookmark: TBufBookmark) : integer;
  231. protected
  232. function GetBookmarkSize: integer; override;
  233. function GetCurrentBuffer: Pointer; override;
  234. function GetCurrentRecord: TRecordBuffer; override;
  235. function GetIsInitialized: boolean; override;
  236. function GetSpareBuffer: TRecordBuffer; override;
  237. function GetSpareRecord: TRecordBuffer; override;
  238. public
  239. FCurrentRecInd : integer;
  240. FRecordArray : array of Pointer;
  241. FLastRecInd : integer;
  242. FNeedScroll : Boolean;
  243. constructor Create(const ADataset: TCustomBufDataset); override;
  244. function ScrollBackward : TGetResult; override;
  245. function ScrollForward : TGetResult; override;
  246. function GetCurrent : TGetResult; override;
  247. function ScrollFirst : TGetResult; override;
  248. procedure ScrollLast; override;
  249. procedure SetToFirstRecord; override;
  250. procedure SetToLastRecord; override;
  251. procedure StoreCurrentRecord; override;
  252. procedure RestoreCurrentRecord; override;
  253. function CanScrollForward : Boolean; override;
  254. procedure DoScrollForward; override;
  255. procedure StoreCurrentRecIntoBookmark(const ABookmark: PBufBookmark); override;
  256. procedure StoreSpareRecIntoBookmark(const ABookmark: PBufBookmark); override;
  257. procedure GotoBookmark(const ABookmark : PBufBookmark); override;
  258. procedure InitialiseIndex; override;
  259. procedure InitialiseSpareRecord(const ASpareRecord : TRecordBuffer); override;
  260. procedure ReleaseSpareRecord; override;
  261. Function GetRecNo(const ABookmark : PBufBookmark) : integer; override;
  262. procedure RemoveRecordFromIndex(const ABookmark : TBufBookmark); override;
  263. procedure InsertRecordBeforeCurrentRecord(Const ARecord : TRecordBuffer); override;
  264. procedure BeginUpdate; override;
  265. procedure AddRecord; override;
  266. procedure EndUpdate; override;
  267. end;
  268. { TBufDatasetReader }
  269. type
  270. TRowStateValue = (rsvOriginal, rsvDeleted, rsvInserted, rsvUpdated, rsvDetailUpdates);
  271. TRowState = set of TRowStateValue;
  272. type
  273. { TDataPacketReader }
  274. TDatapacketReaderClass = class of TDatapacketReader;
  275. TDataPacketReader = class(TObject)
  276. FStream : TStream;
  277. protected
  278. class function RowStateToByte(const ARowState : TRowState) : byte;
  279. class function ByteToRowState(const AByte : Byte) : TRowState;
  280. public
  281. constructor create(AStream : TStream); virtual;
  282. // Load a dataset from stream:
  283. // Load the field-definitions from a stream.
  284. procedure LoadFieldDefs(AFieldDefs : TFieldDefs); virtual; abstract;
  285. // Is called before the records are loaded
  286. procedure InitLoadRecords; virtual; abstract;
  287. // Return the RowState of the current record, and the order of the update
  288. function GetRecordRowState(out AUpdOrder : Integer) : TRowState; virtual; abstract;
  289. // Returns if there is at least one more record available in the stream
  290. function GetCurrentRecord : boolean; virtual; abstract;
  291. // Store a record from stream in the current record-buffer
  292. procedure RestoreRecord(ADataset : TCustomBufDataset); virtual; abstract;
  293. // Move the stream to the next record
  294. procedure GotoNextRecord; virtual; abstract;
  295. // Store a dataset to stream:
  296. // Save the field-definitions to a stream.
  297. procedure StoreFieldDefs(AFieldDefs : TFieldDefs); virtual; abstract;
  298. // Save a record from the current record-buffer to the stream
  299. procedure StoreRecord(ADataset : TCustomBufDataset; ARowState : TRowState; AUpdOrder : integer = 0); virtual; abstract;
  300. // Is called after all records are stored
  301. procedure FinalizeStoreRecords; virtual; abstract;
  302. // Checks if the provided stream is of the right format for this class
  303. class function RecognizeStream(AStream : TStream) : boolean; virtual; abstract;
  304. property Stream: TStream read FStream;
  305. end;
  306. { TFpcBinaryDatapacketReader }
  307. TFpcBinaryDatapacketReader = class(TDataPacketReader)
  308. public
  309. procedure LoadFieldDefs(AFieldDefs : TFieldDefs); override;
  310. procedure StoreFieldDefs(AFieldDefs : TFieldDefs); override;
  311. function GetRecordRowState(out AUpdOrder : Integer) : TRowState; override;
  312. procedure FinalizeStoreRecords; override;
  313. function GetCurrentRecord : boolean; override;
  314. procedure GotoNextRecord; override;
  315. procedure InitLoadRecords; override;
  316. procedure RestoreRecord(ADataset : TCustomBufDataset); override;
  317. procedure StoreRecord(ADataset : TCustomBufDataset; ARowState : TRowState; AUpdOrder : integer = 0); override;
  318. class function RecognizeStream(AStream : TStream) : boolean; override;
  319. end;
  320. TCustomBufDataset = class(TDBDataSet)
  321. private
  322. FFileName: string;
  323. FReadFromFile : boolean;
  324. FFileStream : TFileStream;
  325. FDatasetReader : TDataPacketReader;
  326. FIndexes : array of TBufIndex;
  327. FMaxIndexesCount: integer;
  328. FIndexesCount : integer;
  329. FCurrentIndex : TBufIndex;
  330. FFilterBuffer : TRecordBuffer;
  331. FBRecordCount : integer;
  332. FSavedState : TDatasetState;
  333. FPacketRecords : integer;
  334. FRecordSize : Integer;
  335. FNullmaskSize : byte;
  336. FOpen : Boolean;
  337. FUpdateBuffer : TRecordsUpdateBuffer;
  338. FCurrentUpdateBuffer : integer;
  339. FIndexDefs : TIndexDefs;
  340. FParser : TBufDatasetParser;
  341. FFieldBufPositions : array of longint;
  342. FAllPacketsFetched : boolean;
  343. FOnUpdateError : TResolverErrorEvent;
  344. FBlobBuffers : array of PBlobBuffer;
  345. FUpdateBlobBuffers: array of PBlobBuffer;
  346. procedure FetchAll;
  347. procedure BuildIndex(var AIndex : TBufIndex);
  348. function GetIndexDefs : TIndexDefs;
  349. function GetCurrentBuffer: TRecordBuffer;
  350. procedure CalcRecordSize;
  351. function GetIndexFieldNames: String;
  352. function GetIndexName: String;
  353. function GetBufUniDirectional: boolean;
  354. function LoadBuffer(Buffer : TRecordBuffer): TGetResult;
  355. function GetFieldSize(FieldDef : TFieldDef) : longint;
  356. function GetRecordUpdateBuffer(const ABookmark : TBufBookmark; IncludePrior : boolean = false; AFindNext : boolean = false) : boolean;
  357. function GetRecordUpdateBufferCached(const ABookmark : TBufBookmark; IncludePrior : boolean = false) : boolean;
  358. function GetActiveRecordUpdateBuffer : boolean;
  359. procedure ProcessFieldCompareStruct(AField: TField; var ACompareRec : TDBCompareRec);
  360. procedure SetIndexFieldNames(const AValue: String);
  361. procedure SetIndexName(AValue: String);
  362. procedure SetMaxIndexesCount(const AValue: Integer);
  363. procedure SetPacketRecords(aValue : integer);
  364. function IntAllocRecordBuffer: TRecordBuffer;
  365. procedure ParseFilter(const AFilter: string);
  366. procedure IntLoadFielddefsFromFile;
  367. procedure IntLoadRecordsFromFile;
  368. procedure CurrentRecordToBuffer(Buffer: TRecordBuffer);
  369. procedure SetBufUniDirectional(const AValue: boolean);
  370. procedure InitDefaultIndexes;
  371. protected
  372. procedure UpdateIndexDefs; override;
  373. function GetNewBlobBuffer : PBlobBuffer;
  374. function GetNewWriteBlobBuffer : PBlobBuffer;
  375. procedure FreeBlobBuffer(var ABlobBuffer: PBlobBuffer);
  376. procedure SetRecNo(Value: Longint); override;
  377. function GetRecNo: Longint; override;
  378. function GetChangeCount: integer; virtual;
  379. function AllocRecordBuffer: TRecordBuffer; override;
  380. procedure FreeRecordBuffer(var Buffer: TRecordBuffer); override;
  381. procedure ClearCalcFields(Buffer: TRecordBuffer); override;
  382. procedure InternalInitRecord(Buffer: TRecordBuffer); override;
  383. function GetCanModify: Boolean; override;
  384. function GetRecord(Buffer: TRecordBuffer; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;
  385. procedure DoBeforeClose; override;
  386. procedure InternalOpen; override;
  387. procedure InternalClose; override;
  388. function getnextpacket : integer;
  389. function GetRecordSize: Word; override;
  390. procedure InternalAddIndex(const AName, AFields : string; AOptions : TIndexOptions; const ADescFields: string;
  391. const ACaseInsFields: string); virtual;
  392. procedure InternalPost; override;
  393. procedure InternalCancel; Override;
  394. procedure InternalDelete; override;
  395. procedure InternalFirst; override;
  396. procedure InternalLast; override;
  397. procedure InternalSetToRecord(Buffer: TRecordBuffer); override;
  398. procedure InternalGotoBookmark(ABookmark: Pointer); override;
  399. procedure SetBookmarkData(Buffer: TRecordBuffer; Data: Pointer); override;
  400. procedure SetBookmarkFlag(Buffer: TRecordBuffer; Value: TBookmarkFlag); override;
  401. procedure GetBookmarkData(Buffer: TRecordBuffer; Data: Pointer); override;
  402. function GetBookmarkFlag(Buffer: TRecordBuffer): TBookmarkFlag; override;
  403. function IsCursorOpen: Boolean; override;
  404. function GetRecordCount: Longint; override;
  405. procedure ApplyRecUpdate(UpdateKind : TUpdateKind); virtual;
  406. procedure SetOnUpdateError(const aValue: TResolverErrorEvent);
  407. procedure SetFilterText(const Value: String); override; {virtual;}
  408. procedure SetFiltered(Value: Boolean); override; {virtual;}
  409. procedure InternalRefresh; override;
  410. procedure DataEvent(Event: TDataEvent; Info: Ptrint); override;
  411. procedure BeforeRefreshOpenCursor; virtual;
  412. procedure DoFilterRecord(out Acceptable: Boolean); virtual;
  413. {abstracts, must be overidden by descendents}
  414. function Fetch : boolean; virtual;
  415. function LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; virtual;
  416. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField); virtual; abstract;
  417. function IsReadFromPacket : Boolean;
  418. public
  419. constructor Create(AOwner: TComponent); override;
  420. function GetFieldData(Field: TField; Buffer: Pointer;
  421. NativeFormat: Boolean): Boolean; override;
  422. function GetFieldData(Field: TField; Buffer: Pointer): Boolean; override;
  423. procedure SetFieldData(Field: TField; Buffer: Pointer;
  424. NativeFormat: Boolean); override;
  425. procedure SetFieldData(Field: TField; Buffer: Pointer); override;
  426. procedure ApplyUpdates; virtual; overload;
  427. procedure ApplyUpdates(MaxErrors: Integer); virtual; overload;
  428. procedure CancelUpdates; virtual;
  429. destructor Destroy; override;
  430. function Locate(const keyfields: string; const keyvalues: Variant; options: TLocateOptions) : boolean; override;
  431. function Lookup(const KeyFields: string; const KeyValues: Variant; const ResultFields: string): Variant; override;
  432. function UpdateStatus: TUpdateStatus; override;
  433. function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
  434. procedure AddIndex(const AName, AFields : string; AOptions : TIndexOptions; const ADescFields: string = '';
  435. const ACaseInsFields: string = ''); virtual;
  436. procedure SetDatasetPacket(AReader : TDataPacketReader);
  437. procedure GetDatasetPacket(AWriter : TDataPacketReader);
  438. procedure LoadFromStream(AStream : TStream; Format: TDataPacketFormat = dfAny);
  439. procedure SaveToStream(AStream : TStream; Format: TDataPacketFormat = dfBinary);
  440. procedure LoadFromFile(AFileName: string = ''; Format: TDataPacketFormat = dfAny);
  441. procedure SaveToFile(AFileName: string = ''; Format: TDataPacketFormat = dfBinary);
  442. procedure CreateDataset;
  443. function BookmarkValid(ABookmark: TBookmark): Boolean; override;
  444. function CompareBookmarks(Bookmark1, Bookmark2: TBookmark): Longint; override;
  445. property ChangeCount : Integer read GetChangeCount;
  446. property MaxIndexesCount : Integer read FMaxIndexesCount write SetMaxIndexesCount default 2;
  447. published
  448. property FileName : string read FFileName write FFileName;
  449. property PacketRecords : Integer read FPacketRecords write SetPacketRecords default 10;
  450. property OnUpdateError: TResolverErrorEvent read FOnUpdateError write SetOnUpdateError;
  451. property IndexDefs : TIndexDefs read GetIndexDefs;
  452. property IndexName : String read GetIndexName write SetIndexName;
  453. property IndexFieldNames : String read GetIndexFieldNames write SetIndexFieldNames;
  454. property UniDirectional: boolean read GetBufUniDirectional write SetBufUniDirectional default False;
  455. end;
  456. TBufDataset = class(TCustomBufDataset)
  457. published
  458. property MaxIndexesCount;
  459. // TDataset stuff
  460. property FieldDefs;
  461. Property Active;
  462. Property AutoCalcFields;
  463. Property Filter;
  464. Property Filtered;
  465. Property AfterCancel;
  466. Property AfterClose;
  467. Property AfterDelete;
  468. Property AfterEdit;
  469. Property AfterInsert;
  470. Property AfterOpen;
  471. Property AfterPost;
  472. Property AfterScroll;
  473. Property BeforeCancel;
  474. Property BeforeClose;
  475. Property BeforeDelete;
  476. Property BeforeEdit;
  477. Property BeforeInsert;
  478. Property BeforeOpen;
  479. Property BeforePost;
  480. Property BeforeScroll;
  481. Property OnCalcFields;
  482. Property OnDeleteError;
  483. Property OnEditError;
  484. Property OnFilterRecord;
  485. Property OnNewRecord;
  486. Property OnPostError;
  487. end;
  488. procedure RegisterDatapacketReader(ADatapacketReaderClass : TDatapacketReaderClass; AFormat : TDataPacketFormat);
  489. implementation
  490. uses variants, dbconst, FmtBCD;
  491. Type TDatapacketReaderRegistration = record
  492. ReaderClass : TDatapacketReaderClass;
  493. Format : TDataPacketFormat;
  494. end;
  495. var RegisteredDatapacketReaders : Array of TDatapacketReaderRegistration;
  496. procedure RegisterDatapacketReader(ADatapacketReaderClass : TDatapacketReaderClass; AFormat : TDataPacketFormat);
  497. begin
  498. setlength(RegisteredDatapacketReaders,length(RegisteredDatapacketReaders)+1);
  499. with RegisteredDatapacketReaders[length(RegisteredDatapacketReaders)-1] do
  500. begin
  501. Readerclass := ADatapacketReaderClass;
  502. Format := AFormat;
  503. end;
  504. end;
  505. function GetRegisterDatapacketReader(AStream : TStream; AFormat : TDataPacketFormat; var ADataReaderClass : TDatapacketReaderRegistration) : boolean;
  506. var i : integer;
  507. begin
  508. Result := False;
  509. for i := 0 to length(RegisteredDatapacketReaders)-1 do if ((AFormat=dfAny) or (AFormat=RegisteredDatapacketReaders[i].Format)) then
  510. begin
  511. if (AStream=nil) or (RegisteredDatapacketReaders[i].ReaderClass.RecognizeStream(AStream)) then
  512. begin
  513. ADataReaderClass := RegisteredDatapacketReaders[i];
  514. Result := True;
  515. if (AStream <> nil) then AStream.Seek(0,soFromBeginning);
  516. break;
  517. end;
  518. AStream.Seek(0,soFromBeginning);
  519. end;
  520. end;
  521. function DBCompareText(subValue, aValue: pointer; options: TLocateOptions): LargeInt;
  522. begin
  523. if [loCaseInsensitive,loPartialKey]=options then
  524. Result := AnsiStrLIComp(pchar(subValue),pchar(aValue),length(pchar(subValue)))
  525. else if [loPartialKey] = options then
  526. Result := AnsiStrLComp(pchar(subValue),pchar(aValue),length(pchar(subValue)))
  527. else if [loCaseInsensitive] = options then
  528. Result := AnsiCompareText(pchar(subValue),pchar(aValue))
  529. else
  530. Result := AnsiCompareStr(pchar(subValue),pchar(aValue));
  531. end;
  532. function DBCompareWideText(subValue, aValue: pointer; options: TLocateOptions): LargeInt;
  533. begin
  534. if [loCaseInsensitive,loPartialKey]=options then
  535. Result := WideCompareText(pwidechar(subValue),LeftStr(pwidechar(aValue), Length(pwidechar(subValue))))
  536. else if [loPartialKey] = options then
  537. Result := WideCompareStr(pwidechar(subValue),LeftStr(pwidechar(aValue), Length(pwidechar(subValue))))
  538. else if [loCaseInsensitive] = options then
  539. Result := WideCompareText(pwidechar(subValue),pwidechar(aValue))
  540. else
  541. Result := WideCompareStr(pwidechar(subValue),pwidechar(aValue));
  542. end;
  543. function DBCompareByte(subValue, aValue: pointer; options: TLocateOptions): LargeInt;
  544. begin
  545. Result := PByte(subValue)^-PByte(aValue)^;
  546. end;
  547. function DBCompareSmallInt(subValue, aValue: pointer; options: TLocateOptions): LargeInt;
  548. begin
  549. Result := PSmallInt(subValue)^-PSmallInt(aValue)^;
  550. end;
  551. function DBCompareInt(subValue, aValue: pointer; options: TLocateOptions): LargeInt;
  552. begin
  553. Result := PInteger(subValue)^-PInteger(aValue)^;
  554. end;
  555. function DBCompareLargeInt(subValue, aValue: pointer; options: TLocateOptions): LargeInt;
  556. begin
  557. // A simple subtraction doesn't work, since it could be that the result
  558. // doesn't fit into a LargeInt
  559. if PLargeInt(subValue)^ < PLargeInt(aValue)^ then
  560. result := -1
  561. else if PLargeInt(subValue)^ > PLargeInt(aValue)^ then
  562. result := 1
  563. else
  564. result := 0;
  565. end;
  566. function DBCompareWord(subValue, aValue: pointer; options: TLocateOptions): LargeInt;
  567. begin
  568. Result := PWord(subValue)^-PWord(aValue)^;
  569. end;
  570. function DBCompareQWord(subValue, aValue: pointer; options: TLocateOptions): LargeInt;
  571. begin
  572. // A simple subtraction doesn't work, since it could be that the result
  573. // doesn't fit into a LargeInt
  574. if PQWord(subValue)^ < PQWord(aValue)^ then
  575. result := -1
  576. else if PQWord(subValue)^ > PQWord(aValue)^ then
  577. result := 1
  578. else
  579. result := 0;
  580. end;
  581. function DBCompareDouble(subValue, aValue: pointer; options: TLocateOptions): LargeInt;
  582. begin
  583. // A simple subtraction doesn't work, since it could be that the result
  584. // doesn't fit into a LargeInt
  585. if PDouble(subValue)^ < PDouble(aValue)^ then
  586. result := -1
  587. else if PDouble(subValue)^ > PDouble(aValue)^ then
  588. result := 1
  589. else
  590. result := 0;
  591. end;
  592. function DBCompareBCD(subValue, aValue: pointer; options: TLocateOptions): LargeInt;
  593. begin
  594. result:=BCDCompare(PBCD(subValue)^, PBCD(aValue)^);
  595. end;
  596. procedure unSetFieldIsNull(NullMask : pbyte;x : longint); //inline;
  597. begin
  598. NullMask[x div 8] := (NullMask[x div 8]) and not (1 shl (x mod 8));
  599. end;
  600. procedure SetFieldIsNull(NullMask : pbyte;x : longint); //inline;
  601. begin
  602. NullMask[x div 8] := (NullMask[x div 8]) or (1 shl (x mod 8));
  603. end;
  604. function GetFieldIsNull(NullMask : pbyte;x : longint) : boolean; //inline;
  605. begin
  606. result := ord(NullMask[x div 8]) and (1 shl (x mod 8)) > 0
  607. end;
  608. function IndexCompareRecords(Rec1,Rec2 : pointer; ADBCompareRecs : TDBCompareStruct) : LargeInt;
  609. var IndexFieldNr : Integer;
  610. IsNull1, IsNull2 : boolean;
  611. begin
  612. for IndexFieldNr:=0 to length(ADBCompareRecs)-1 do with ADBCompareRecs[IndexFieldNr] do
  613. begin
  614. IsNull1:=GetFieldIsNull(rec1+NullBOff1,FieldInd1);
  615. IsNull2:=GetFieldIsNull(rec2+NullBOff2,FieldInd2);
  616. if IsNull1 and IsNull2 then
  617. result := 0
  618. else if IsNull1 then
  619. result := -1
  620. else if IsNull2 then
  621. result := 1
  622. else
  623. Result := Comparefunc(Rec1+Off1,Rec2+Off2,Options);
  624. if Result <> 0 then
  625. begin
  626. if Desc then
  627. Result := -Result;
  628. break;
  629. end;
  630. end;
  631. end;
  632. { ---------------------------------------------------------------------
  633. TCustomBufDataset
  634. ---------------------------------------------------------------------}
  635. constructor TCustomBufDataset.Create(AOwner : TComponent);
  636. begin
  637. Inherited Create(AOwner);
  638. FMaxIndexesCount:=2;
  639. FIndexesCount:=0;
  640. FIndexDefs := TIndexDefs.Create(Self);
  641. SetLength(FUpdateBuffer,0);
  642. SetLength(FBlobBuffers,0);
  643. SetLength(FUpdateBlobBuffers,0);
  644. FParser := nil;
  645. FPacketRecords := 10;
  646. end;
  647. procedure TCustomBufDataset.SetPacketRecords(aValue : integer);
  648. begin
  649. if (aValue = -1) or (aValue > 0) then FPacketRecords := aValue
  650. else DatabaseError(SInvPacketRecordsValue);
  651. end;
  652. destructor TCustomBufDataset.Destroy;
  653. Var
  654. I : Integer;
  655. begin
  656. if Active then Close;
  657. SetLength(FUpdateBuffer,0);
  658. SetLength(FBlobBuffers,0);
  659. SetLength(FUpdateBlobBuffers,0);
  660. For I:=0 to Length(FIndexes)-1 do
  661. FreeAndNil(Findexes[I]);
  662. SetLength(FIndexes,0);
  663. FreeAndNil(FIndexDefs);
  664. inherited destroy;
  665. end;
  666. procedure TCustomBufDataset.FetchAll;
  667. begin
  668. repeat
  669. until (getnextpacket < FPacketRecords) or (FPacketRecords = -1);
  670. end;
  671. {
  672. // Code to dump raw dataset data, including indexes information, usefull for debugging
  673. procedure DumpRawMem(const Data: pointer; ALength: PtrInt);
  674. var
  675. b: integer;
  676. s1,s2: string;
  677. begin
  678. s1 := '';
  679. s2 := '';
  680. for b := 0 to ALength-1 do
  681. begin
  682. s1 := s1 + ' ' + hexStr(pbyte(Data)[b],2);
  683. if pchar(Data)[b] in ['a'..'z','A'..'Z','1'..'9',' '..'/',':'..'@'] then
  684. s2 := s2 + pchar(Data)[b]
  685. else
  686. s2 := s2 + '.';
  687. if length(s2)=16 then
  688. begin
  689. write(' ',s1,' ');
  690. writeln(s2);
  691. s1 := '';
  692. s2 := '';
  693. end;
  694. end;
  695. write(' ',s1,' ');
  696. writeln(s2);
  697. end;
  698. procedure DumpRecord(Dataset: TCustomBufDataset; RecBuf: PBufRecLinkItem; RawData: boolean = false);
  699. var ptr: pointer;
  700. NullMask: pointer;
  701. FieldData: pointer;
  702. NullMaskSize: integer;
  703. i: integer;
  704. begin
  705. if RawData then
  706. DumpRawMem(RecBuf,Dataset.RecordSize)
  707. else
  708. begin
  709. ptr := RecBuf;
  710. NullMask:= ptr + (sizeof(TBufRecLinkItem)*Dataset.MaxIndexesCount);
  711. NullMaskSize := 1+(Dataset.Fields.Count-1) div 8;
  712. FieldData:= ptr + (sizeof(TBufRecLinkItem)*Dataset.MaxIndexesCount) +NullMaskSize;
  713. write('record: $',hexstr(ptr),' nullmask: $');
  714. for i := 0 to NullMaskSize-1 do
  715. write(hexStr(byte((NullMask+i)^),2));
  716. write('=');
  717. for i := 0 to NullMaskSize-1 do
  718. write(binStr(byte((NullMask+i)^),8));
  719. writeln('%');
  720. for i := 0 to Dataset.MaxIndexesCount-1 do
  721. writeln(' ','Index ',inttostr(i),' Prior rec: ' + hexstr(pointer((ptr+(i*2)*sizeof(ptr))^)) + ' Next rec: ' + hexstr(pointer((ptr+((i*2)+1)*sizeof(ptr))^)));
  722. DumpRawMem(FieldData,Dataset.RecordSize-((sizeof(TBufRecLinkItem)*Dataset.MaxIndexesCount) +NullMaskSize));
  723. end;
  724. end;
  725. procedure DumpDataset(AIndex: TBufIndex;RawData: boolean = false);
  726. var RecBuf: PBufRecLinkItem;
  727. begin
  728. writeln('Dump records, order based on index ',AIndex.IndNr);
  729. writeln('Current record:',hexstr(AIndex.CurrentRecord));
  730. RecBuf:=(AIndex as TDoubleLinkedBufIndex).FFirstRecBuf;
  731. while RecBuf<>(AIndex as TDoubleLinkedBufIndex).FLastRecBuf do
  732. begin
  733. DumpRecord(AIndex.FDataset,RecBuf,RawData);
  734. RecBuf:=RecBuf[(AIndex as TDoubleLinkedBufIndex).IndNr].next;
  735. end;
  736. end;
  737. }
  738. procedure TCustomBufDataset.BuildIndex(var AIndex: TBufIndex);
  739. var PCurRecLinkItem : PBufRecLinkItem;
  740. p,l,q : PBufRecLinkItem;
  741. i,k,psize,qsize : integer;
  742. MergeAmount : integer;
  743. PlaceQRec : boolean;
  744. IndexFields : TList;
  745. DescIndexFields : TList;
  746. CInsIndexFields : TList;
  747. FieldsAmount : Integer;
  748. FieldNr : integer;
  749. AField : TField;
  750. Index0,
  751. DblLinkIndex : TDoubleLinkedBufIndex;
  752. procedure PlaceNewRec(var e: PBufRecLinkItem; var esize: integer);
  753. begin
  754. if DblLinkIndex.FFirstRecBuf=nil then
  755. begin
  756. DblLinkIndex.FFirstRecBuf:=e;
  757. e[DblLinkIndex.IndNr].prior:=nil;
  758. l:=e;
  759. end
  760. else
  761. begin
  762. l[DblLinkIndex.IndNr].next:=e;
  763. e[DblLinkIndex.IndNr].prior:=l;
  764. l:=e;
  765. end;
  766. e := e[DblLinkIndex.IndNr].next;
  767. dec(esize);
  768. end;
  769. begin
  770. // Build the DBCompareStructure
  771. // One AS is enough, and makes debugging easier.
  772. DblLinkIndex:=(AIndex as TDoubleLinkedBufIndex);
  773. Index0:=(FIndexes[0] as TDoubleLinkedBufIndex);
  774. with DblLinkIndex do
  775. begin
  776. IndexFields := TList.Create;
  777. DescIndexFields := TList.Create;
  778. CInsIndexFields := TList.Create;
  779. try
  780. GetFieldList(IndexFields,FieldsName);
  781. FieldsAmount:=IndexFields.Count;
  782. GetFieldList(DescIndexFields,DescFields);
  783. GetFieldList(CInsIndexFields,CaseinsFields);
  784. if FieldsAmount=0 then
  785. DatabaseError(SNoIndexFieldNameGiven);
  786. SetLength(DBCompareStruct,FieldsAmount);
  787. for FieldNr:=0 to FieldsAmount-1 do
  788. begin
  789. AField := TField(IndexFields[FieldNr]);
  790. ProcessFieldCompareStruct(AField,DBCompareStruct[FieldNr]);
  791. DBCompareStruct[FieldNr].Desc := (DescIndexFields.IndexOf(AField)>-1) or (ixDescending in Options);
  792. if (CInsIndexFields.IndexOf(AField)>-1) then
  793. DBCompareStruct[FieldNr].Options := [loCaseInsensitive]
  794. else
  795. DBCompareStruct[FieldNr].Options := [];
  796. end;
  797. finally
  798. CInsIndexFields.Free;
  799. DescIndexFields.Free;
  800. IndexFields.Free;
  801. end;
  802. end;
  803. // This simply copies the index...
  804. PCurRecLinkItem:=Index0.FFirstRecBuf;
  805. PCurRecLinkItem[DblLinkIndex.IndNr].next := PCurRecLinkItem[0].next;
  806. PCurRecLinkItem[DblLinkIndex.IndNr].prior := PCurRecLinkItem[0].prior;
  807. if PCurRecLinkItem <> Index0.FLastRecBuf then
  808. begin
  809. while PCurRecLinkItem^.next<>Index0.FLastRecBuf do
  810. begin
  811. PCurRecLinkItem:=PCurRecLinkItem^.next;
  812. PCurRecLinkItem[DblLinkIndex.IndNr].next := PCurRecLinkItem[0].next;
  813. PCurRecLinkItem[DblLinkIndex.IndNr].prior := PCurRecLinkItem[0].prior;
  814. end;
  815. end
  816. else
  817. // Empty dataset
  818. Exit;
  819. // Set FirstRecBuf and FCurrentRecBuf
  820. DblLinkIndex.FFirstRecBuf:=Index0.FFirstRecBuf;
  821. DblLinkIndex.FCurrentRecBuf:=DblLinkIndex.FFirstRecBuf;
  822. // Link in the FLastRecBuf that belongs to this index
  823. PCurRecLinkItem[DblLinkIndex.IndNr].next:=DblLinkIndex.FLastRecBuf;
  824. DblLinkIndex.FLastRecBuf[DblLinkIndex.IndNr].prior:=PCurRecLinkItem;
  825. // Mergesort. Used the algorithm as described here by Simon Tatham
  826. // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
  827. // The comments in the code are from this website.
  828. // In each pass, we are merging lists of size K into lists of size 2K.
  829. // (Initially K equals 1.)
  830. k:=1;
  831. repeat
  832. // So we start by pointing a temporary pointer p at the head of the list,
  833. // and also preparing an empty list L which we will add elements to the end
  834. // of as we finish dealing with them.
  835. p := DblLinkIndex.FFirstRecBuf;
  836. DblLinkIndex.FFirstRecBuf := nil;
  837. q := p;
  838. MergeAmount := 0;
  839. // Then:
  840. // * If p is null, terminate this pass.
  841. while p <> DblLinkIndex.FLastRecBuf do
  842. begin
  843. // * Otherwise, there is at least one element in the next pair of length-K
  844. // lists, so increment the number of merges performed in this pass.
  845. inc(MergeAmount);
  846. // * Point another temporary pointer, q, at the same place as p. Step q along
  847. // the list by K places, or until the end of the list, whichever comes
  848. // first. Let psize be the number of elements you managed to step q past.
  849. i:=0;
  850. while (i<k) and (q<>DblLinkIndex.FLastRecBuf) do
  851. begin
  852. inc(i);
  853. q := q[DblLinkIndex.IndNr].next;
  854. end;
  855. psize :=i;
  856. // * Let qsize equal K. Now we need to merge a list starting at p, of length
  857. // psize, with a list starting at q of length at most qsize.
  858. qsize:=k;
  859. // * So, as long as either the p-list is non-empty (psize > 0) or the q-list
  860. // is non-empty (qsize > 0 and q points to something non-null):
  861. while (psize>0) or ((qsize>0) and (q <> DblLinkIndex.FLastRecBuf)) do
  862. begin
  863. // o Choose which list to take the next element from. If either list
  864. // is empty, we must choose from the other one. (By assumption, at
  865. // least one is non-empty at this point.) If both lists are
  866. // non-empty, compare the first element of each and choose the lower
  867. // one. If the first elements compare equal, choose from the p-list.
  868. // (This ensures that any two elements which compare equal are never
  869. // swapped, so stability is guaranteed.)
  870. if (psize=0) then
  871. PlaceQRec := true
  872. else if (qsize=0) or (q = DblLinkIndex.FLastRecBuf) then
  873. PlaceQRec := False
  874. else if IndexCompareRecords(p,q,DblLinkIndex.DBCompareStruct) <= 0 then
  875. PlaceQRec := False
  876. else
  877. PlaceQRec := True;
  878. // o Remove that element, e, from the start of its list, by advancing
  879. // p or q to the next element along, and decrementing psize or qsize.
  880. // o Add e to the end of the list L we are building up.
  881. if PlaceQRec then
  882. PlaceNewRec(q,qsize)
  883. else
  884. PlaceNewRec(p,psize);
  885. end;
  886. // * Now we have advanced p until it is where q started out, and we have
  887. // advanced q until it is pointing at the next pair of length-K lists to
  888. // merge. So set p to the value of q, and go back to the start of this loop.
  889. p:=q;
  890. end;
  891. // As soon as a pass like this is performed and only needs to do one merge, the
  892. // algorithm terminates, and the output list L is sorted. Otherwise, double the
  893. // value of K, and go back to the beginning.
  894. l[DblLinkIndex.IndNr].next:=DblLinkIndex.FLastRecBuf;
  895. k:=k*2;
  896. until MergeAmount = 1;
  897. DblLinkIndex.FLastRecBuf[DblLinkIndex.IndNr].next:=DblLinkIndex.FFirstRecBuf;
  898. DblLinkIndex.FLastRecBuf[DblLinkIndex.IndNr].prior:=l;
  899. end;
  900. function TCustomBufDataset.GetIndexDefs : TIndexDefs;
  901. begin
  902. Result := FIndexDefs;
  903. end;
  904. procedure TCustomBufDataset.UpdateIndexDefs;
  905. var i : integer;
  906. begin
  907. FIndexDefs.Clear;
  908. for i := 0 to high(FIndexes) do with FIndexDefs.AddIndexDef do
  909. begin
  910. Name := FIndexes[i].Name;
  911. Fields := FIndexes[i].FieldsName;
  912. DescFields:= FIndexes[i].DescFields;
  913. CaseInsFields:=FIndexes[i].CaseinsFields;
  914. Options:=FIndexes[i].Options;
  915. end;
  916. end;
  917. Function TCustomBufDataset.GetCanModify: Boolean;
  918. begin
  919. Result:= True;
  920. end;
  921. function TCustomBufDataset.IntAllocRecordBuffer: TRecordBuffer;
  922. begin
  923. // Note: Only the internal buffers of TDataset provide bookmark information
  924. result := AllocMem(FRecordsize+sizeof(TBufRecLinkItem)*FMaxIndexesCount);
  925. end;
  926. function TCustomBufDataset.AllocRecordBuffer: TRecordBuffer;
  927. begin
  928. result := AllocMem(FRecordsize + BookmarkSize + CalcfieldsSize);
  929. // The records are initialised, or else the fields of an empty, just-opened dataset
  930. // are not null
  931. InitRecord(result);
  932. end;
  933. procedure TCustomBufDataset.FreeRecordBuffer(var Buffer: TRecordBuffer);
  934. begin
  935. ReAllocMem(Buffer,0);
  936. end;
  937. procedure TCustomBufDataset.ClearCalcFields(Buffer: TRecordBuffer);
  938. begin
  939. if CalcFieldsSize > 0 then
  940. FillByte((Buffer+RecordSize)^,CalcFieldsSize,0);
  941. end;
  942. procedure TCustomBufDataset.InternalOpen;
  943. var IndexNr : integer;
  944. begin
  945. InitDefaultIndexes;
  946. if not Assigned(FDatasetReader) and (FileName<>'') then
  947. begin
  948. FFileStream := TFileStream.Create(FileName,fmOpenRead);
  949. FDatasetReader := TFpcBinaryDatapacketReader.Create(FFileStream);
  950. FReadFromFile := True;
  951. end;
  952. if assigned(FDatasetReader) then IntLoadFielddefsFromFile;
  953. CalcRecordSize;
  954. FBRecordcount := 0;
  955. for IndexNr:=0 to FIndexesCount-1 do with FIndexes[IndexNr] do
  956. InitialiseSpareRecord(IntAllocRecordBuffer);
  957. FAllPacketsFetched := False;
  958. FOpen:=True;
  959. // parse filter expression
  960. try
  961. ParseFilter(Filter);
  962. except
  963. // oops, a problem with parsing, clear filter for now
  964. on E: Exception do Filter := EmptyStr;
  965. end;
  966. if assigned(FDatasetReader) then IntLoadRecordsFromFile;
  967. end;
  968. procedure TCustomBufDataset.InternalClose;
  969. var r : integer;
  970. iGetResult : TGetResult;
  971. pc : TRecordBuffer;
  972. begin
  973. FOpen:=False;
  974. if FIndexesCount>0 then with FIndexes[0] do if IsInitialized then
  975. begin
  976. iGetResult:=ScrollFirst;
  977. while iGetResult = grOK do
  978. begin
  979. pc := pointer(CurrentRecord);
  980. iGetResult:=ScrollForward;
  981. FreeRecordBuffer(pc);
  982. end;
  983. end;
  984. for r := 0 to FIndexesCount-1 do with FIndexes[r] do if IsInitialized then
  985. begin
  986. pc := SpareRecord;
  987. ReleaseSpareRecord;
  988. FreeRecordBuffer(pc);
  989. end;
  990. if Length(FUpdateBuffer) > 0 then
  991. begin
  992. for r := 0 to length(FUpdateBuffer)-1 do with FUpdateBuffer[r] do
  993. begin
  994. if assigned(OldValuesBuffer) then
  995. FreeRecordBuffer(OldValuesBuffer);
  996. end;
  997. end;
  998. SetLength(FUpdateBuffer,0);
  999. for r := 0 to High(FBlobBuffers) do
  1000. FreeBlobBuffer(FBlobBuffers[r]);
  1001. for r := 0 to High(FUpdateBlobBuffers) do
  1002. FreeBlobBuffer(FUpdateBlobBuffers[r]);
  1003. SetLength(FBlobBuffers,0);
  1004. SetLength(FUpdateBlobBuffers,0);
  1005. SetLength(FFieldBufPositions,0);
  1006. if assigned(FParser) then FreeAndNil(FParser);
  1007. FReadFromFile:=false;
  1008. end;
  1009. procedure TCustomBufDataset.InternalFirst;
  1010. begin
  1011. with FCurrentIndex do
  1012. begin
  1013. // if FCurrentRecBuf = FLastRecBuf then the dataset is just opened and empty
  1014. // in which case InternalFirst should do nothing (bug 7211)
  1015. SetToFirstRecord;
  1016. end;
  1017. end;
  1018. procedure TCustomBufDataset.InternalLast;
  1019. begin
  1020. FetchAll;
  1021. with FCurrentIndex do
  1022. SetToLastRecord;
  1023. end;
  1024. function TDoubleLinkedBufIndex.GetCurrentRecord: TRecordBuffer;
  1025. begin
  1026. Result := TRecordBuffer(FCurrentRecBuf);
  1027. end;
  1028. function TDoubleLinkedBufIndex.GetBookmarkSize: integer;
  1029. begin
  1030. Result:=sizeof(TBufBookmark);
  1031. end;
  1032. function TDoubleLinkedBufIndex.GetCurrentBuffer: Pointer;
  1033. begin
  1034. Result := pointer(FCurrentRecBuf)+(sizeof(TBufRecLinkItem)*FDataset.MaxIndexesCount);
  1035. end;
  1036. function TDoubleLinkedBufIndex.GetIsInitialized: boolean;
  1037. begin
  1038. Result := (FFirstRecBuf<>nil);
  1039. end;
  1040. function TDoubleLinkedBufIndex.GetSpareBuffer: TRecordBuffer;
  1041. begin
  1042. Result := pointer(FLastRecBuf)+(sizeof(TBufRecLinkItem)*FDataset.MaxIndexesCount);
  1043. end;
  1044. function TDoubleLinkedBufIndex.GetSpareRecord: TRecordBuffer;
  1045. begin
  1046. Result := TRecordBuffer(FLastRecBuf);
  1047. end;
  1048. constructor TBufIndex.Create(const ADataset: TCustomBufDataset);
  1049. begin
  1050. inherited create;
  1051. FDataset := ADataset;
  1052. end;
  1053. function TBufIndex.BookmarkValid(const ABookmark: PBufBookmark): boolean;
  1054. begin
  1055. Result := assigned(ABookmark) and assigned(ABookmark^.BookmarkData);
  1056. end;
  1057. function TBufIndex.CompareBookmarks(const ABookmark1, ABookmark2: PBufBookmark): boolean;
  1058. begin
  1059. result := (ABookmark1^.BookmarkData=ABookmark2^.BookmarkData);
  1060. end;
  1061. function TDoubleLinkedBufIndex.ScrollBackward: TGetResult;
  1062. begin
  1063. if not assigned(FCurrentRecBuf[IndNr].prior) then
  1064. begin
  1065. Result := grBOF;
  1066. end
  1067. else
  1068. begin
  1069. Result := grOK;
  1070. FCurrentRecBuf := FCurrentRecBuf[IndNr].prior;
  1071. end;
  1072. end;
  1073. function TDoubleLinkedBufIndex.ScrollForward: TGetResult;
  1074. begin
  1075. if (FCurrentRecBuf = FLastRecBuf) or // just opened
  1076. (FCurrentRecBuf[IndNr].next = FLastRecBuf) then
  1077. result := grEOF
  1078. else
  1079. begin
  1080. FCurrentRecBuf := FCurrentRecBuf[IndNr].next;
  1081. Result := grOK;
  1082. end;
  1083. end;
  1084. function TDoubleLinkedBufIndex.GetCurrent: TGetResult;
  1085. begin
  1086. if FFirstRecBuf = FLastRecBuf then
  1087. Result := grError
  1088. else
  1089. begin
  1090. Result := grOK;
  1091. if FCurrentRecBuf = FLastRecBuf then
  1092. FCurrentRecBuf:=FLastRecBuf[IndNr].prior;
  1093. end;
  1094. end;
  1095. function TDoubleLinkedBufIndex.ScrollFirst: TGetResult;
  1096. begin
  1097. FCurrentRecBuf:=FFirstRecBuf;
  1098. if (FCurrentRecBuf = FLastRecBuf) then
  1099. result := grEOF
  1100. else
  1101. result := grOK;
  1102. end;
  1103. procedure TDoubleLinkedBufIndex.ScrollLast;
  1104. begin
  1105. FCurrentRecBuf:=FLastRecBuf;
  1106. end;
  1107. procedure TDoubleLinkedBufIndex.SetToFirstRecord;
  1108. begin
  1109. FLastRecBuf[IndNr].next:=FFirstRecBuf;
  1110. FCurrentRecBuf := FLastRecBuf;
  1111. end;
  1112. procedure TDoubleLinkedBufIndex.SetToLastRecord;
  1113. begin
  1114. if FLastRecBuf <> FFirstRecBuf then FCurrentRecBuf := FLastRecBuf;
  1115. end;
  1116. procedure TDoubleLinkedBufIndex.StoreCurrentRecord;
  1117. begin
  1118. FStoredRecBuf:=FCurrentRecBuf;
  1119. end;
  1120. procedure TDoubleLinkedBufIndex.RestoreCurrentRecord;
  1121. begin
  1122. FCurrentRecBuf:=FStoredRecBuf;
  1123. end;
  1124. procedure TDoubleLinkedBufIndex.DoScrollForward;
  1125. begin
  1126. FCurrentRecBuf := FCurrentRecBuf[IndNr].next;
  1127. end;
  1128. procedure TDoubleLinkedBufIndex.StoreCurrentRecIntoBookmark(const ABookmark: PBufBookmark);
  1129. begin
  1130. ABookmark^.BookmarkData:=FCurrentRecBuf;
  1131. end;
  1132. procedure TDoubleLinkedBufIndex.StoreSpareRecIntoBookmark(
  1133. const ABookmark: PBufBookmark);
  1134. begin
  1135. ABookmark^.BookmarkData:=FLastRecBuf;
  1136. end;
  1137. procedure TDoubleLinkedBufIndex.GotoBookmark(const ABookmark : PBufBookmark);
  1138. begin
  1139. FCurrentRecBuf := ABookmark^.BookmarkData;
  1140. end;
  1141. procedure TDoubleLinkedBufIndex.InitialiseIndex;
  1142. begin
  1143. // Do nothing
  1144. end;
  1145. function TDoubleLinkedBufIndex.CanScrollForward: Boolean;
  1146. begin
  1147. if (FCurrentRecBuf[IndNr].next = FLastRecBuf) then
  1148. Result := False
  1149. else
  1150. Result := True;
  1151. end;
  1152. procedure TDoubleLinkedBufIndex.InitialiseSpareRecord(const ASpareRecord : TRecordBuffer);
  1153. begin
  1154. FFirstRecBuf := pointer(ASpareRecord);
  1155. FLastRecBuf := FFirstRecBuf;
  1156. FLastRecBuf[IndNr].prior:=nil;
  1157. FLastRecBuf[IndNr].next:=FLastRecBuf;
  1158. FCurrentRecBuf := FLastRecBuf;
  1159. end;
  1160. procedure TDoubleLinkedBufIndex.ReleaseSpareRecord;
  1161. begin
  1162. FFirstRecBuf:= nil;
  1163. end;
  1164. procedure TDoubleLinkedBufIndex.RemoveRecordFromIndex(const ABookmark : TBufBookmark);
  1165. var ARecord : PBufRecLinkItem;
  1166. begin
  1167. ARecord := ABookmark.BookmarkData;
  1168. if ARecord = FCurrentRecBuf then DoScrollForward;
  1169. if ARecord <> FFirstRecBuf then
  1170. ARecord[IndNr].prior[IndNr].next := ARecord[IndNr].next
  1171. else
  1172. begin
  1173. FFirstRecBuf := ARecord[IndNr].next;
  1174. FLastRecBuf[IndNr].next := FFirstRecBuf;
  1175. end;
  1176. ARecord[IndNr].next[IndNr].prior := ARecord[IndNr].prior;
  1177. end;
  1178. function TDoubleLinkedBufIndex.GetRecNo(const ABookmark: PBufBookmark): integer;
  1179. Var TmpRecBuffer : PBufRecLinkItem;
  1180. recnr : integer;
  1181. begin
  1182. TmpRecBuffer := FFirstRecBuf;
  1183. recnr := 1;
  1184. while TmpRecBuffer <> ABookmark^.BookmarkData do
  1185. begin
  1186. inc(recnr);
  1187. TmpRecBuffer := TmpRecBuffer[IndNr].next;
  1188. end;
  1189. Result := recnr;
  1190. end;
  1191. procedure TDoubleLinkedBufIndex.BeginUpdate;
  1192. begin
  1193. if FCurrentRecBuf = FLastRecBuf then
  1194. FCursOnFirstRec := True
  1195. else
  1196. FCursOnFirstRec := False;
  1197. end;
  1198. procedure TDoubleLinkedBufIndex.AddRecord;
  1199. var ARecord: TRecordBuffer;
  1200. begin
  1201. ARecord := FDataset.IntAllocRecordBuffer;
  1202. FLastRecBuf[IndNr].next := pointer(ARecord);
  1203. FLastRecBuf[IndNr].next[IndNr].prior := FLastRecBuf;
  1204. FLastRecBuf := FLastRecBuf[IndNr].next;
  1205. end;
  1206. procedure TDoubleLinkedBufIndex.InsertRecordBeforeCurrentRecord(const ARecord: TRecordBuffer);
  1207. var ANewRecord : PBufRecLinkItem;
  1208. begin
  1209. ANewRecord:=PBufRecLinkItem(ARecord);
  1210. ANewRecord[IndNr].prior:=FCurrentRecBuf[IndNr].prior;
  1211. ANewRecord[IndNr].Next:=FCurrentRecBuf;
  1212. if FCurrentRecBuf=FFirstRecBuf then
  1213. begin
  1214. FFirstRecBuf:=ANewRecord;
  1215. ANewRecord[IndNr].prior:=nil;
  1216. end
  1217. else
  1218. ANewRecord[IndNr].Prior[IndNr].next:=ANewRecord;
  1219. ANewRecord[IndNr].next[IndNr].prior:=ANewRecord;
  1220. end;
  1221. procedure TDoubleLinkedBufIndex.EndUpdate;
  1222. begin
  1223. FLastRecBuf[IndNr].next := FFirstRecBuf;
  1224. if FCursOnFirstRec then FCurrentRecBuf:=FLastRecBuf;
  1225. end;
  1226. procedure TCustomBufDataset.CurrentRecordToBuffer(Buffer: TRecordBuffer);
  1227. var ABookMark : PBufBookmark;
  1228. begin
  1229. with FCurrentIndex do
  1230. begin
  1231. move(CurrentBuffer^,buffer^,FRecordSize);
  1232. ABookMark:=PBufBookmark(Buffer + FRecordSize);
  1233. ABookmark^.BookmarkFlag:=bfCurrent;
  1234. StoreCurrentRecIntoBookmark(ABookMark);
  1235. end;
  1236. GetCalcFields(Buffer);
  1237. end;
  1238. procedure TCustomBufDataset.SetBufUniDirectional(const AValue: boolean);
  1239. begin
  1240. CheckInactive;
  1241. if (AValue<>IsUniDirectional) then
  1242. begin
  1243. SetUniDirectional(AValue);
  1244. SetLength(FIndexes,0);
  1245. FPacketRecords := 1; // temporary
  1246. FIndexesCount:=0;
  1247. end;
  1248. end;
  1249. procedure TCustomBufDataset.InitDefaultIndexes;
  1250. begin
  1251. if FIndexesCount=0 then
  1252. begin
  1253. InternalAddIndex('DEFAULT_ORDER','',[],'','');
  1254. FCurrentIndex:=FIndexes[0];
  1255. if not IsUniDirectional then
  1256. InternalAddIndex('','',[],'','');
  1257. BookmarkSize := FCurrentIndex.BookmarkSize;
  1258. end;
  1259. end;
  1260. function TCustomBufDataset.GetRecord(Buffer: TRecordBuffer; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
  1261. var Acceptable : Boolean;
  1262. SaveState : TDataSetState;
  1263. begin
  1264. Result := grOK;
  1265. with FCurrentIndex do
  1266. begin
  1267. repeat
  1268. Acceptable := True;
  1269. case GetMode of
  1270. gmPrior : Result := ScrollBackward;
  1271. gmCurrent : Result := GetCurrent;
  1272. gmNext : begin
  1273. if not CanScrollForward and (getnextpacket = 0) then result := grEOF
  1274. else
  1275. begin
  1276. result := grOK;
  1277. DoScrollForward;
  1278. end;
  1279. end;
  1280. end;
  1281. if Result = grOK then
  1282. begin
  1283. CurrentRecordToBuffer(buffer);
  1284. if Filtered then
  1285. begin
  1286. FFilterBuffer := Buffer;
  1287. SaveState := SetTempState(dsFilter);
  1288. DoFilterRecord(Acceptable);
  1289. if (GetMode = gmCurrent) and not Acceptable then
  1290. begin
  1291. Acceptable := True;
  1292. Result := grError;
  1293. end;
  1294. RestoreState(SaveState);
  1295. end;
  1296. end
  1297. else if (Result = grError) and doCheck then
  1298. DatabaseError('No record');
  1299. until Acceptable;
  1300. end;
  1301. end;
  1302. procedure TCustomBufDataset.DoBeforeClose;
  1303. begin
  1304. inherited DoBeforeClose;
  1305. if FFileName<>'' then
  1306. SaveToFile(FFileName);
  1307. end;
  1308. function TCustomBufDataset.GetActiveRecordUpdateBuffer : boolean;
  1309. var ABookmark : TBufBookmark;
  1310. begin
  1311. GetBookmarkData(ActiveBuffer,@ABookmark);
  1312. result := GetRecordUpdateBufferCached(ABookmark);
  1313. end;
  1314. procedure TCustomBufDataset.ProcessFieldCompareStruct(AField: TField; var ACompareRec : TDBCompareRec);
  1315. begin
  1316. case AField.DataType of
  1317. ftString, ftFixedChar : ACompareRec.Comparefunc := @DBCompareText;
  1318. ftWideString, ftFixedWideChar: ACompareRec.Comparefunc := @DBCompareWideText;
  1319. ftSmallint : ACompareRec.Comparefunc := @DBCompareSmallInt;
  1320. ftInteger, ftBCD, ftAutoInc : ACompareRec.Comparefunc :=
  1321. @DBCompareInt;
  1322. ftWord : ACompareRec.Comparefunc := @DBCompareWord;
  1323. ftBoolean : ACompareRec.Comparefunc := @DBCompareByte;
  1324. ftFloat, ftCurrency : ACompareRec.Comparefunc := @DBCompareDouble;
  1325. ftDateTime, ftDate, ftTime : ACompareRec.Comparefunc :=
  1326. @DBCompareDouble;
  1327. ftLargeint : ACompareRec.Comparefunc := @DBCompareLargeInt;
  1328. ftFmtBCD : ACompareRec.Comparefunc := @DBCompareBCD;
  1329. else
  1330. DatabaseErrorFmt(SErrIndexBasedOnInvField, [AField.FieldName,Fieldtypenames[AField.DataType]]);
  1331. end;
  1332. ACompareRec.Off1:=sizeof(TBufRecLinkItem)*FMaxIndexesCount+
  1333. FFieldBufPositions[AField.FieldNo-1];
  1334. ACompareRec.Off2:=ACompareRec.Off1;
  1335. ACompareRec.FieldInd1:=AField.FieldNo-1;
  1336. ACompareRec.FieldInd2:=ACompareRec.FieldInd1;
  1337. ACompareRec.NullBOff1:=sizeof(TBufRecLinkItem)*MaxIndexesCount;
  1338. ACompareRec.NullBOff2:=ACompareRec.NullBOff1;
  1339. end;
  1340. procedure TCustomBufDataset.SetIndexFieldNames(const AValue: String);
  1341. begin
  1342. if AValue<>'' then
  1343. begin
  1344. if FIndexesCount=0 then
  1345. InitDefaultIndexes;
  1346. FIndexes[1].FieldsName:=AValue;
  1347. FCurrentIndex:=FIndexes[1];
  1348. if active then
  1349. begin
  1350. FetchAll;
  1351. BuildIndex(FIndexes[1]);
  1352. Resync([rmCenter]);
  1353. end;
  1354. end
  1355. else
  1356. SetIndexName('');
  1357. end;
  1358. procedure TCustomBufDataset.SetIndexName(AValue: String);
  1359. var i : integer;
  1360. begin
  1361. if AValue='' then AValue := 'DEFAULT_ORDER';
  1362. for i := 0 to FIndexesCount-1 do
  1363. if SameText(FIndexes[i].Name,AValue) then
  1364. begin
  1365. (FIndexes[i] as TDoubleLinkedBufIndex).FCurrentRecBuf:=(FCurrentIndex as TDoubleLinkedBufIndex).FCurrentRecBuf;
  1366. FCurrentIndex:=FIndexes[i];
  1367. if active then Resync([rmCenter]);
  1368. exit;
  1369. end;
  1370. end;
  1371. procedure TCustomBufDataset.SetMaxIndexesCount(const AValue: Integer);
  1372. begin
  1373. CheckInactive;
  1374. if AValue > 1 then
  1375. FMaxIndexesCount:=AValue
  1376. else
  1377. DatabaseError(SMinIndexes);
  1378. end;
  1379. procedure TCustomBufDataset.InternalSetToRecord(Buffer: TRecordBuffer);
  1380. begin
  1381. FCurrentIndex.GotoBookmark(PBufBookmark(Buffer+FRecordSize));
  1382. end;
  1383. procedure TCustomBufDataset.SetBookmarkData(Buffer: TRecordBuffer; Data: Pointer);
  1384. begin
  1385. PBufBookmark(Buffer + FRecordSize)^ := PBufBookmark(Data)^;
  1386. end;
  1387. procedure TCustomBufDataset.SetBookmarkFlag(Buffer: TRecordBuffer; Value: TBookmarkFlag);
  1388. begin
  1389. PBufBookmark(Buffer + FRecordSize)^.BookmarkFlag := Value;
  1390. end;
  1391. procedure TCustomBufDataset.GetBookmarkData(Buffer: TRecordBuffer; Data: Pointer);
  1392. begin
  1393. PBufBookmark(Data)^ := PBufBookmark(Buffer + FRecordSize)^;
  1394. end;
  1395. function TCustomBufDataset.GetBookmarkFlag(Buffer: TRecordBuffer): TBookmarkFlag;
  1396. begin
  1397. Result := PBufBookmark(Buffer + FRecordSize)^.BookmarkFlag;
  1398. end;
  1399. procedure TCustomBufDataset.InternalGotoBookmark(ABookmark: Pointer);
  1400. begin
  1401. // note that ABookMark should be a PBufBookmark. But this way it can also be
  1402. // a pointer to a TBufRecLinkItem
  1403. FCurrentIndex.GotoBookmark(ABookmark);
  1404. end;
  1405. function TCustomBufDataset.getnextpacket : integer;
  1406. var i : integer;
  1407. pb : TRecordBuffer;
  1408. begin
  1409. if FAllPacketsFetched then
  1410. begin
  1411. result := 0;
  1412. exit;
  1413. end;
  1414. FCurrentIndex.BeginUpdate;
  1415. i := 0;
  1416. pb := FIndexes[0].SpareBuffer;
  1417. while ((i < FPacketRecords) or (FPacketRecords = -1)) and (loadbuffer(pb) = grOk) do
  1418. begin
  1419. with FIndexes[0] do
  1420. begin
  1421. AddRecord;
  1422. pb := SpareBuffer;
  1423. end;
  1424. inc(i);
  1425. end;
  1426. FCurrentIndex.EndUpdate;
  1427. FBRecordCount := FBRecordCount + i;
  1428. result := i;
  1429. end;
  1430. function TCustomBufDataset.GetFieldSize(FieldDef : TFieldDef) : longint;
  1431. begin
  1432. case FieldDef.DataType of
  1433. ftUnknown : result := 0;
  1434. ftString,
  1435. ftGuid,
  1436. ftFixedChar: result := FieldDef.Size + 1;
  1437. ftFixedWideChar,
  1438. ftWideString:result := (FieldDef.Size + 1)*2;
  1439. ftSmallint,
  1440. ftInteger,
  1441. ftAutoInc,
  1442. ftword : result := sizeof(longint);
  1443. ftBoolean : result := sizeof(wordbool);
  1444. ftBCD : result := sizeof(currency);
  1445. ftFmtBCD : result := sizeof(TBCD);
  1446. ftFloat,
  1447. ftCurrency : result := sizeof(double);
  1448. ftLargeInt : result := sizeof(largeint);
  1449. ftTime,
  1450. ftDate,
  1451. ftDateTime : result := sizeof(TDateTime);
  1452. ftBytes : result := FieldDef.Size;
  1453. ftVarBytes : result := FieldDef.Size + 2;
  1454. ftVariant : result := sizeof(variant);
  1455. ftBlob,
  1456. ftMemo,
  1457. ftGraphic,
  1458. ftFmtMemo,
  1459. ftParadoxOle,
  1460. ftDBaseOle,
  1461. ftTypedBinary,
  1462. ftOraBlob,
  1463. ftOraClob,
  1464. ftWideMemo : result := sizeof(TBufBlobField)
  1465. else
  1466. DatabaseErrorFmt(SUnsupportedFieldType,[Fieldtypenames[FieldDef.DataType]]);
  1467. end;
  1468. {$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT}
  1469. result:=Align(result,4);
  1470. {$ENDIF}
  1471. end;
  1472. function TCustomBufDataset.GetRecordUpdateBuffer(const ABookmark : TBufBookmark; IncludePrior : boolean = false; AFindNext : boolean = false): boolean;
  1473. var x : integer;
  1474. StartBuf : integer;
  1475. begin
  1476. if AFindNext then
  1477. StartBuf := FCurrentUpdateBuffer + 1
  1478. else
  1479. StartBuf := 0;
  1480. Result := False;
  1481. for x := StartBuf to high(FUpdateBuffer) do
  1482. if FCurrentIndex.CompareBookmarks(@FUpdateBuffer[x].BookmarkData,@ABookmark) or
  1483. (IncludePrior and (FUpdateBuffer[x].UpdateKind=ukDelete) and FCurrentIndex.CompareBookmarks(@FUpdateBuffer[x].NextBookmarkData,@ABookmark)) then
  1484. begin
  1485. FCurrentUpdateBuffer := x;
  1486. Result := True;
  1487. break;
  1488. end;
  1489. end;
  1490. function TCustomBufDataset.GetRecordUpdateBufferCached(const ABookmark: TBufBookmark;
  1491. IncludePrior: boolean): boolean;
  1492. begin
  1493. // if the current update buffer complies, immediately return true
  1494. if (FCurrentUpdateBuffer < length(FUpdateBuffer)) and (
  1495. FCurrentIndex.CompareBookmarks(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData,@ABookmark) or
  1496. (IncludePrior and (FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind=ukDelete) and FCurrentIndex.CompareBookmarks(@FUpdateBuffer[FCurrentUpdateBuffer].NextBookmarkData,@ABookmark))) then
  1497. Result := True
  1498. else
  1499. Result := GetRecordUpdateBuffer(ABookmark,IncludePrior);
  1500. end;
  1501. function TCustomBufDataset.LoadBuffer(Buffer : TRecordBuffer): TGetResult;
  1502. var NullMask : pbyte;
  1503. x : longint;
  1504. CreateblobField : boolean;
  1505. BufBlob : PBufBlobField;
  1506. begin
  1507. if not Fetch then
  1508. begin
  1509. Result := grEOF;
  1510. FAllPacketsFetched := True;
  1511. // This code has to be placed elsewhere. At least it should also run when
  1512. // the datapacket is loaded from file ... see IntLoadRecordsFromFile
  1513. if FIndexesCount>0 then for x := 1 to FIndexesCount-1 do
  1514. begin
  1515. if not ((x=1) and (FIndexes[1].FieldsName='')) then
  1516. BuildIndex(FIndexes[x]);
  1517. end;
  1518. Exit;
  1519. end;
  1520. NullMask := pointer(buffer);
  1521. fillchar(Nullmask^,FNullmaskSize,0);
  1522. inc(buffer,FNullmaskSize);
  1523. for x := 0 to FieldDefs.count-1 do
  1524. begin
  1525. if not LoadField(FieldDefs[x],buffer,CreateblobField) then
  1526. SetFieldIsNull(NullMask,x)
  1527. else if CreateblobField then
  1528. begin
  1529. BufBlob := PBufBlobField(Buffer);
  1530. BufBlob^.BlobBuffer := GetNewBlobBuffer;
  1531. LoadBlobIntoBuffer(FieldDefs[x],BufBlob);
  1532. end;
  1533. inc(buffer,GetFieldSize(FieldDefs[x]));
  1534. end;
  1535. Result := grOK;
  1536. end;
  1537. function TCustomBufDataset.GetCurrentBuffer: TRecordBuffer;
  1538. begin
  1539. if State = dsFilter then Result := FFilterBuffer
  1540. else if state = dsCalcFields then Result := CalcBuffer
  1541. else Result := ActiveBuffer;
  1542. end;
  1543. function TCustomBufDataset.GetFieldData(Field: TField; Buffer: Pointer;
  1544. NativeFormat: Boolean): Boolean;
  1545. begin
  1546. Result := GetFieldData(Field, Buffer);
  1547. end;
  1548. function TCustomBufDataset.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
  1549. var CurrBuff : TRecordBuffer;
  1550. begin
  1551. Result := False;
  1552. if State = dsOldValue then
  1553. begin
  1554. if FSavedState = dsInsert then
  1555. CurrBuff := nil // old values = null
  1556. else if GetActiveRecordUpdateBuffer then
  1557. CurrBuff := FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer
  1558. else
  1559. // There is no UpdateBuffer for ActiveRecord, so there are no explicit old values available
  1560. // then we can assume, that old values = current values
  1561. CurrBuff := FCurrentIndex.CurrentBuffer;
  1562. end
  1563. else
  1564. CurrBuff := GetCurrentBuffer;
  1565. if not assigned(CurrBuff) then Exit;
  1566. If Field.Fieldno > 0 then // If = 0, then calculated field or something similar
  1567. begin
  1568. if GetFieldIsNull(pbyte(CurrBuff),Field.FieldNo-1) then
  1569. Exit;
  1570. if assigned(buffer) then
  1571. begin
  1572. inc(CurrBuff,FFieldBufPositions[Field.FieldNo-1]);
  1573. Move(CurrBuff^, Buffer^, GetFieldSize(FieldDefs[Field.FieldNo-1]));
  1574. end;
  1575. Result := True;
  1576. end
  1577. else
  1578. begin
  1579. Inc(CurrBuff, GetRecordSize + Field.Offset);
  1580. Result := Boolean(CurrBuff^);
  1581. if result and assigned(Buffer) then
  1582. begin
  1583. inc(CurrBuff);
  1584. Move(CurrBuff^, Buffer^, Field.Datasize);
  1585. end;
  1586. end;
  1587. end;
  1588. procedure TCustomBufDataset.SetFieldData(Field: TField; Buffer: Pointer;
  1589. NativeFormat: Boolean);
  1590. begin
  1591. SetFieldData(Field,Buffer);
  1592. end;
  1593. procedure TCustomBufDataset.SetFieldData(Field: TField; Buffer: Pointer);
  1594. var CurrBuff : pointer;
  1595. NullMask : pbyte;
  1596. begin
  1597. if not (State in dsWriteModes) then
  1598. DatabaseError(SNotEditing, Self);
  1599. CurrBuff := GetCurrentBuffer;
  1600. If Field.Fieldno > 0 then // If = 0, then calculated field or something
  1601. begin
  1602. if Field.ReadOnly and not (State in [dsSetKey, dsFilter]) then
  1603. DatabaseErrorFmt(SReadOnlyField, [Field.DisplayName]);
  1604. if State in [dsEdit, dsInsert, dsNewValue] then
  1605. Field.Validate(Buffer);
  1606. NullMask := CurrBuff;
  1607. inc(CurrBuff,FFieldBufPositions[Field.FieldNo-1]);
  1608. if assigned(buffer) then
  1609. begin
  1610. Move(Buffer^, CurrBuff^, GetFieldSize(FieldDefs[Field.FieldNo-1]));
  1611. unSetFieldIsNull(NullMask,Field.FieldNo-1);
  1612. end
  1613. else
  1614. SetFieldIsNull(NullMask,Field.FieldNo-1);
  1615. end
  1616. else
  1617. begin
  1618. Inc(CurrBuff, GetRecordSize + Field.Offset);
  1619. Boolean(CurrBuff^) := Buffer <> nil;
  1620. inc(CurrBuff);
  1621. if assigned(Buffer) then
  1622. Move(Buffer^, CurrBuff^, Field.Datasize);
  1623. end;
  1624. if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
  1625. DataEvent(deFieldChange, Ptrint(Field));
  1626. end;
  1627. procedure TCustomBufDataset.InternalDelete;
  1628. var i : Integer;
  1629. RemRec, FreeRec : pointer;
  1630. RemRecBookmrk : TBufBookmark;
  1631. begin
  1632. InternalSetToRecord(ActiveBuffer);
  1633. // Remove the record from all active indexes
  1634. FCurrentIndex.StoreCurrentRecIntoBookmark(@RemRecBookmrk);
  1635. RemRec := FCurrentIndex.CurrentBuffer;
  1636. for i := 0 to FIndexesCount-1 do
  1637. if (i<>1) or (FIndexes[i]=FCurrentIndex) then
  1638. FIndexes[i].RemoveRecordFromIndex(RemRecBookmrk);
  1639. if not GetActiveRecordUpdateBuffer then
  1640. begin
  1641. FCurrentUpdateBuffer := length(FUpdateBuffer);
  1642. SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
  1643. FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := IntAllocRecordBuffer;
  1644. move(RemRec^, FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize);
  1645. end
  1646. else //with FIndexes[0] do
  1647. begin
  1648. if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind <> ukModify then
  1649. begin
  1650. FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := nil; //this 'disables' the updatebuffer
  1651. FreeRec := RemRecBookmrk.BookmarkData; // mantis #18004
  1652. FreeRecordBuffer(TRecordBuffer(FreeRec));
  1653. // RemRecBookmrk.BookmarkData still points to just freed record buffer
  1654. // There could be record in update-buffer, linked to this record
  1655. end;
  1656. end;
  1657. FCurrentIndex.StoreCurrentRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].NextBookmarkData);
  1658. FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData := RemRecBookmrk;
  1659. FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukDelete;
  1660. dec(FBRecordCount);
  1661. end;
  1662. procedure TCustomBufDataset.ApplyRecUpdate(UpdateKind : TUpdateKind);
  1663. begin
  1664. raise EDatabaseError.Create(SApplyRecNotSupported);
  1665. end;
  1666. procedure TCustomBufDataset.CancelUpdates;
  1667. var StoreRecBM : TBufBookmark;
  1668. procedure CancelUpdBuffer(var AUpdBuffer : TRecUpdateBuffer);
  1669. var
  1670. TmpBuf : TRecordBuffer;
  1671. StoreUpdBuf : integer;
  1672. Bm : TBufBookmark;
  1673. begin
  1674. with AUpdBuffer do if assigned(BookmarkData.BookmarkData) then // this is used to exclude buffers which are already handled
  1675. begin
  1676. if (UpdateKind = ukModify) then
  1677. begin
  1678. FCurrentIndex.GotoBookmark(@BookmarkData);
  1679. move(TRecordBuffer(OldValuesBuffer)^,TRecordBuffer(FCurrentIndex.CurrentBuffer)^,FRecordSize);
  1680. FreeRecordBuffer(OldValuesBuffer);
  1681. end
  1682. else if (UpdateKind = ukDelete) and (assigned(OldValuesBuffer)) then
  1683. begin
  1684. FCurrentIndex.GotoBookmark(@NextBookmarkData);
  1685. FCurrentIndex.InsertRecordBeforeCurrentRecord(TRecordBuffer(BookmarkData.BookmarkData));
  1686. FCurrentIndex.ScrollBackward;
  1687. move(TRecordBuffer(OldValuesBuffer)^,TRecordBuffer(FCurrentIndex.CurrentBuffer)^,FRecordSize);
  1688. { for x := length(FUpdateBuffer)-1 downto 0 do
  1689. begin
  1690. if (FUpdateBuffer[x].UpdateKind=ukDelete) and FCurrentIndex.CompareBookmarks(@FUpdateBuffer[x].NextBookmarkData,@BookmarkData) then
  1691. CancelUpdBuffer(FUpdateBuffer[x]);
  1692. end;}
  1693. FreeRecordBuffer(OldValuesBuffer);
  1694. inc(FBRecordCount);
  1695. end
  1696. else if (UpdateKind = ukInsert) then
  1697. begin
  1698. // Process all upd-buffers linked to this record before this record is removed
  1699. StoreUpdBuf:=FCurrentUpdateBuffer;
  1700. Bm := BookmarkData;
  1701. BookmarkData.BookmarkData:=nil; // Avoid infinite recursion...
  1702. if GetRecordUpdateBuffer(Bm,True,False) then
  1703. begin
  1704. repeat
  1705. if (FCurrentUpdateBuffer<>StoreUpdBuf) then CancelUpdBuffer(FUpdateBuffer[FCurrentUpdateBuffer]);
  1706. until not GetRecordUpdateBuffer(Bm,True,True);
  1707. end;
  1708. FCurrentUpdateBuffer:=StoreUpdBuf;
  1709. FCurrentIndex.GotoBookmark(@Bm);
  1710. TmpBuf:=FCurrentIndex.CurrentRecord;
  1711. // resync won't work if the currentbuffer is freed...
  1712. if FCurrentIndex.CompareBookmarks(@Bm,@StoreRecBM) then with FCurrentIndex do
  1713. begin
  1714. GotoBookmark(@StoreRecBM);
  1715. if ScrollForward = grEOF then
  1716. ScrollBackward;
  1717. StoreCurrentRecIntoBookmark(@StoreRecBM);
  1718. end;
  1719. FCurrentIndex.RemoveRecordFromIndex(Bm);
  1720. FreeRecordBuffer(TmpBuf);
  1721. dec(FBRecordCount);
  1722. end;
  1723. BookmarkData.BookmarkData:=nil;
  1724. end;
  1725. end;
  1726. var r : Integer;
  1727. begin
  1728. CheckBrowseMode;
  1729. if Length(FUpdateBuffer) > 0 then
  1730. begin
  1731. FCurrentIndex.StoreCurrentRecIntoBookmark(@StoreRecBM);
  1732. for r := Length(FUpdateBuffer) - 1 downto 0 do
  1733. CancelUpdBuffer(FUpdateBuffer[r]);
  1734. SetLength(FUpdateBuffer,0);
  1735. FCurrentIndex.GotoBookmark(@StoreRecBM);
  1736. Resync([]);
  1737. end;
  1738. end;
  1739. procedure TCustomBufDataset.SetOnUpdateError(const AValue: TResolverErrorEvent);
  1740. begin
  1741. FOnUpdateError := AValue;
  1742. end;
  1743. procedure TCustomBufDataset.ApplyUpdates; // For backwards-compatibility
  1744. begin
  1745. ApplyUpdates(0);
  1746. end;
  1747. procedure TCustomBufDataset.ApplyUpdates(MaxErrors: Integer);
  1748. var r : Integer;
  1749. FailedCount : integer;
  1750. Response : TResolverResponse;
  1751. StoreCurrRec : TBufBookmark;
  1752. AUpdateErr : EUpdateError;
  1753. begin
  1754. CheckBrowseMode;
  1755. FCurrentIndex.StoreCurrentRecIntoBookmark(@StoreCurrRec);
  1756. r := 0;
  1757. FailedCount := 0;
  1758. Response := rrApply;
  1759. DisableControls;
  1760. try
  1761. while (r < Length(FUpdateBuffer)) and (Response <> rrAbort) do
  1762. begin
  1763. // If the record is first inserted and afterwards deleted, do nothing
  1764. if not ((FUpdateBuffer[r].UpdateKind=ukDelete) and not (assigned(FUpdateBuffer[r].OldValuesBuffer))) then
  1765. begin
  1766. FCurrentIndex.GotoBookmark(@FUpdateBuffer[r].BookmarkData);
  1767. // Synchronise the Currentbuffer to the ActiveBuffer
  1768. CurrentRecordToBuffer(ActiveBuffer);
  1769. Response := rrApply;
  1770. try
  1771. ApplyRecUpdate(FUpdateBuffer[r].UpdateKind);
  1772. except
  1773. on E: EDatabaseError do
  1774. begin
  1775. Inc(FailedCount);
  1776. if failedcount > word(MaxErrors) then Response := rrAbort
  1777. else Response := rrSkip;
  1778. if assigned(FOnUpdateError) then
  1779. begin
  1780. AUpdateErr := EUpdateError.Create(SOnUpdateError,E.Message,0,0,Exception(AcquireExceptionObject));
  1781. FOnUpdateError(Self,Self,AUpdateErr,FUpdateBuffer[r].UpdateKind,Response);
  1782. AUpdateErr.Free;
  1783. if Response in [rrApply, rrIgnore] then dec(FailedCount);
  1784. if Response = rrApply then dec(r);
  1785. end
  1786. else if Response = rrAbort then
  1787. Raise EUpdateError.Create(SOnUpdateError,E.Message,0,0,Exception(AcquireExceptionObject));
  1788. end
  1789. else
  1790. raise;
  1791. end;
  1792. if response in [rrApply, rrIgnore] then
  1793. begin
  1794. FreeRecordBuffer(FUpdateBuffer[r].OldValuesBuffer);
  1795. if FUpdateBuffer[r].UpdateKind = ukDelete then
  1796. FreeRecordBuffer( TRecordBuffer(FUpdateBuffer[r].BookmarkData.BookmarkData));
  1797. FUpdateBuffer[r].BookmarkData.BookmarkData := nil;
  1798. end
  1799. end;
  1800. inc(r);
  1801. end;
  1802. finally
  1803. if failedcount = 0 then
  1804. begin
  1805. SetLength(FUpdateBuffer,0);
  1806. if assigned(FUpdateBlobBuffers) then for r:=0 to length(FUpdateBlobBuffers)-1 do
  1807. if assigned(FUpdateBlobBuffers[r]) then
  1808. begin
  1809. if FUpdateBlobBuffers[r]^.OrgBufID >= 0 then
  1810. begin
  1811. Freemem(FBlobBuffers[FUpdateBlobBuffers[r]^.OrgBufID]^.Buffer);
  1812. Dispose(FBlobBuffers[FUpdateBlobBuffers[r]^.OrgBufID]);
  1813. FBlobBuffers[FUpdateBlobBuffers[r]^.OrgBufID] :=FUpdateBlobBuffers[r];
  1814. end
  1815. else
  1816. begin
  1817. setlength(FBlobBuffers,length(FBlobBuffers)+1);
  1818. FUpdateBlobBuffers[r]^.OrgBufID := high(FBlobBuffers);
  1819. FBlobBuffers[high(FBlobBuffers)] := FUpdateBlobBuffers[r];
  1820. end;
  1821. end;
  1822. SetLength(FUpdateBlobBuffers,0);
  1823. end;
  1824. InternalGotoBookmark(@StoreCurrRec);
  1825. Resync([]);
  1826. EnableControls;
  1827. end;
  1828. end;
  1829. procedure TCustomBufDataset.InternalCancel;
  1830. Var i : integer;
  1831. begin
  1832. if assigned(FUpdateBlobBuffers) then for i:=0 to length(FUpdateBlobBuffers)-1 do
  1833. if assigned(FUpdateBlobBuffers[i]) and (FUpdateBlobBuffers[i]^.FieldNo>0) then
  1834. begin
  1835. Reallocmem(FUpdateBlobBuffers[i]^.Buffer,0);
  1836. Dispose(FUpdateBlobBuffers[i]);
  1837. FUpdateBlobBuffers[i] := nil;
  1838. end;
  1839. end;
  1840. procedure TCustomBufDataset.InternalPost;
  1841. Var ABuff : TRecordBuffer;
  1842. i : integer;
  1843. blobbuf : tbufblobfield;
  1844. NullMask : pbyte;
  1845. ABookmark : PBufBookmark;
  1846. begin
  1847. inherited InternalPost;
  1848. if assigned(FUpdateBlobBuffers) then for i:=0 to length(FUpdateBlobBuffers)-1 do
  1849. if assigned(FUpdateBlobBuffers[i]) and (FUpdateBlobBuffers[i]^.FieldNo>0) then
  1850. begin
  1851. blobbuf.BlobBuffer := FUpdateBlobBuffers[i];
  1852. ABuff := ActiveBuffer;
  1853. NullMask := PByte(ABuff);
  1854. inc(ABuff,FFieldBufPositions[FUpdateBlobBuffers[i]^.FieldNo-1]);
  1855. Move(blobbuf, ABuff^, GetFieldSize(FieldDefs[FUpdateBlobBuffers[i]^.FieldNo-1]));
  1856. unSetFieldIsNull(NullMask,FUpdateBlobBuffers[i]^.FieldNo-1);
  1857. FUpdateBlobBuffers[i]^.FieldNo := -1;
  1858. end;
  1859. if State = dsInsert then
  1860. begin
  1861. // The active buffer is the newly created TDataset record,
  1862. // from which the bookmark is set to the record where the new record should be
  1863. // inserted
  1864. ABookmark := PBufBookmark(ActiveBuffer + FRecordSize);
  1865. // Create the new record buffer
  1866. ABuff := IntAllocRecordBuffer;
  1867. // Add new record to all active indexes
  1868. for i := 0 to FIndexesCount-1 do
  1869. if (i<>1) or (FIndexes[i]=FCurrentIndex) then
  1870. begin
  1871. if ABookmark^.BookmarkFlag = bfEOF then
  1872. // append (at end)
  1873. FIndexes[i].ScrollLast
  1874. else
  1875. // insert (before current record)
  1876. FIndexes[i].GotoBookmark(ABookmark);
  1877. FIndexes[i].InsertRecordBeforeCurrentRecord(ABuff);
  1878. // new inserted record becomes current record
  1879. FIndexes[i].ScrollBackward;
  1880. end;
  1881. // Link the newly created record buffer to the newly created TDataset record
  1882. with ABookmark^ do
  1883. begin
  1884. FCurrentIndex.StoreCurrentRecIntoBookmark(@BookmarkData);
  1885. BookmarkFlag := bfInserted;
  1886. end;
  1887. inc(FBRecordCount);
  1888. end
  1889. else
  1890. InternalSetToRecord(ActiveBuffer);
  1891. // If there is no updatebuffer already, add one
  1892. if not GetActiveRecordUpdateBuffer then
  1893. begin
  1894. // Add a new updatebuffer
  1895. FCurrentUpdateBuffer := length(FUpdateBuffer);
  1896. SetLength(FUpdateBuffer,FCurrentUpdateBuffer+1);
  1897. // Store a bookmark of the current record into the updatebuffer's bookmark
  1898. FCurrentIndex.StoreCurrentRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData);
  1899. if state = dsEdit then
  1900. begin
  1901. // Create an oldvalues buffer with the old values of the record
  1902. FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := IntAllocRecordBuffer;
  1903. with FCurrentIndex do
  1904. // Move only the real data
  1905. move(CurrentBuffer^,FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer^,FRecordSize);
  1906. FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukModify;
  1907. end
  1908. else
  1909. begin
  1910. FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind := ukInsert;
  1911. FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := nil;
  1912. end;
  1913. end;
  1914. move(ActiveBuffer^,FCurrentIndex.CurrentBuffer^,FRecordSize);
  1915. end;
  1916. procedure TCustomBufDataset.CalcRecordSize;
  1917. var x : longint;
  1918. begin
  1919. FNullmaskSize := 1+((FieldDefs.count-1) div 8);
  1920. {$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT}
  1921. FNullmaskSize:=Align(FNullmaskSize,4);
  1922. {$ENDIF}
  1923. FRecordSize := FNullmaskSize;
  1924. SetLength(FFieldBufPositions,FieldDefs.count);
  1925. for x := 0 to FieldDefs.count-1 do
  1926. begin
  1927. FFieldBufPositions[x] := FRecordSize;
  1928. inc(FRecordSize, GetFieldSize(FieldDefs[x]));
  1929. end;
  1930. end;
  1931. function TCustomBufDataset.GetIndexFieldNames: String;
  1932. begin
  1933. if (FIndexesCount=0) or (FCurrentIndex<>FIndexes[1]) then
  1934. result := ''
  1935. else
  1936. result := FCurrentIndex.FieldsName;
  1937. end;
  1938. function TCustomBufDataset.GetIndexName: String;
  1939. begin
  1940. if FIndexesCount>0 then
  1941. result := FCurrentIndex.Name
  1942. else
  1943. result := '';
  1944. end;
  1945. function TCustomBufDataset.GetBufUniDirectional: boolean;
  1946. begin
  1947. result := IsUniDirectional;
  1948. end;
  1949. function TCustomBufDataset.GetRecordSize : Word;
  1950. begin
  1951. result := FRecordSize + BookmarkSize;
  1952. end;
  1953. function TCustomBufDataset.GetChangeCount: integer;
  1954. begin
  1955. result := length(FUpdateBuffer);
  1956. end;
  1957. procedure TCustomBufDataset.InternalInitRecord(Buffer: TRecordBuffer);
  1958. begin
  1959. FillChar(Buffer^, FRecordSize, #0);
  1960. fillchar(Buffer^,FNullmaskSize,255);
  1961. end;
  1962. procedure TCustomBufDataset.SetRecNo(Value: Longint);
  1963. var
  1964. recnr : integer;
  1965. TmpRecBuffer : PBufRecLinkItem;
  1966. begin
  1967. checkbrowsemode;
  1968. if value > RecordCount then
  1969. begin
  1970. repeat until (getnextpacket < FPacketRecords) or (value <= RecordCount) or (FPacketRecords = -1);
  1971. if value > RecordCount then
  1972. begin
  1973. DatabaseError(SNoSuchRecord,self);
  1974. exit;
  1975. end;
  1976. end;
  1977. TmpRecBuffer := (FCurrentIndex as TDoubleLinkedBufIndex).FFirstRecBuf;
  1978. for recnr := 1 to value-1 do
  1979. TmpRecBuffer := TmpRecBuffer[FCurrentIndex.IndNr].next;
  1980. GotoBookmark(@TmpRecBuffer);
  1981. end;
  1982. function TCustomBufDataset.GetRecNo: Longint;
  1983. Var abuf : TRecordBuffer;
  1984. begin
  1985. abuf := GetCurrentBuffer;
  1986. // If abuf isn't assigned, the recordset probably isn't opened.
  1987. if assigned(abuf) and (FBRecordCount>0) and (state <> dsInsert) then
  1988. Result:=FCurrentIndex.GetRecNo(PBufBookmark(abuf+FRecordSize))
  1989. else
  1990. result := 0;
  1991. end;
  1992. function TCustomBufDataset.IsCursorOpen: Boolean;
  1993. begin
  1994. Result := FOpen;
  1995. end;
  1996. Function TCustomBufDataset.GetRecordCount: Longint;
  1997. begin
  1998. Result := FBRecordCount;
  1999. end;
  2000. Function TCustomBufDataset.UpdateStatus: TUpdateStatus;
  2001. begin
  2002. Result:=usUnmodified;
  2003. if GetActiveRecordUpdateBuffer then
  2004. case FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind of
  2005. ukModify : Result := usModified;
  2006. ukInsert : Result := usInserted;
  2007. ukDelete : Result := usDeleted;
  2008. end;
  2009. end;
  2010. function TCustomBufDataset.GetNewBlobBuffer : PBlobBuffer;
  2011. var ABlobBuffer : PBlobBuffer;
  2012. begin
  2013. setlength(FBlobBuffers,length(FBlobBuffers)+1);
  2014. new(ABlobBuffer);
  2015. fillbyte(ABlobBuffer^,sizeof(ABlobBuffer^),0);
  2016. ABlobBuffer^.OrgBufID := high(FUpdateBlobBuffers);
  2017. FBlobBuffers[high(FBlobBuffers)] := ABlobBuffer;
  2018. result := ABlobBuffer;
  2019. end;
  2020. function TCustomBufDataset.GetNewWriteBlobBuffer : PBlobBuffer;
  2021. var ABlobBuffer : PBlobBuffer;
  2022. begin
  2023. setlength(FUpdateBlobBuffers,length(FUpdateBlobBuffers)+1);
  2024. new(ABlobBuffer);
  2025. fillbyte(ABlobBuffer^,sizeof(ABlobBuffer^),0);
  2026. FUpdateBlobBuffers[high(FUpdateBlobBuffers)] := ABlobBuffer;
  2027. result := ABlobBuffer;
  2028. end;
  2029. procedure TCustomBufDataset.FreeBlobBuffer(var ABlobBuffer: PBlobBuffer);
  2030. begin
  2031. if not Assigned(ABlobBuffer) then Exit;
  2032. FreeMem(ABlobBuffer^.Buffer, ABlobBuffer^.Size);
  2033. Dispose(ABlobBuffer);
  2034. ABlobBuffer := Nil;
  2035. end;
  2036. function TBufBlobStream.Seek(Offset: Longint; Origin: Word): Longint;
  2037. begin
  2038. Case Origin of
  2039. soFromBeginning : FPosition:=Offset;
  2040. soFromEnd : FPosition:=FBlobBuffer^.Size+Offset;
  2041. soFromCurrent : FpoSition:=FPosition+Offset;
  2042. end;
  2043. Result:=FPosition;
  2044. end;
  2045. function TBufBlobStream.Read(var Buffer; Count: Longint): Longint;
  2046. var ptr : pointer;
  2047. begin
  2048. if FPosition + count > FBlobBuffer^.Size then
  2049. count := FBlobBuffer^.Size-FPosition;
  2050. ptr := FBlobBuffer^.Buffer+FPosition;
  2051. move(ptr^,buffer,count);
  2052. inc(FPosition,count);
  2053. result := count;
  2054. end;
  2055. function TBufBlobStream.Write(const Buffer; Count: Longint): Longint;
  2056. var ptr : pointer;
  2057. begin
  2058. ReAllocMem(FBlobBuffer^.Buffer,FPosition+Count);
  2059. ptr := FBlobBuffer^.Buffer+FPosition;
  2060. move(buffer,ptr^,count);
  2061. inc(FBlobBuffer^.Size,count);
  2062. inc(FPosition,count);
  2063. Result := count;
  2064. end;
  2065. constructor TBufBlobStream.Create(Field: TBlobField; Mode: TBlobStreamMode);
  2066. var bufblob : TBufBlobField;
  2067. begin
  2068. FDataset := Field.DataSet as TCustomBufDataset;
  2069. if mode = bmread then
  2070. begin
  2071. if not field.getData(@bufblob) then
  2072. DatabaseError(SFieldIsNull);
  2073. if not assigned(bufblob.BlobBuffer) then with FDataSet do
  2074. begin
  2075. FBlobBuffer := GetNewBlobBuffer;
  2076. bufblob.BlobBuffer := FBlobBuffer;
  2077. LoadBlobIntoBuffer(FieldDefs[field.FieldNo-1],@bufblob);
  2078. end
  2079. else
  2080. FBlobBuffer := bufblob.BlobBuffer;
  2081. end
  2082. else if mode=bmWrite then with FDataSet as TCustomBufDataset do
  2083. begin
  2084. FBlobBuffer := GetNewWriteBlobBuffer;
  2085. FBlobBuffer^.FieldNo := Field.FieldNo;
  2086. if (field.getData(@bufblob)) and assigned(bufblob.BlobBuffer) then
  2087. FBlobBuffer^.OrgBufID := bufblob.BlobBuffer^.OrgBufID
  2088. else
  2089. FBlobBuffer^.OrgBufID := -1;
  2090. end;
  2091. end;
  2092. function TCustomBufDataset.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
  2093. var bufblob : TBufBlobField;
  2094. begin
  2095. result := nil;
  2096. if mode=bmread then
  2097. begin
  2098. if not field.getData(@bufblob) then
  2099. exit;
  2100. result := TBufBlobStream.Create(Field as tblobfield,bmread);
  2101. end
  2102. else if mode=bmWrite then
  2103. begin
  2104. if not (state in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then
  2105. begin
  2106. DatabaseErrorFmt(SNotEditing,[Name],self);
  2107. exit;
  2108. end;
  2109. result := TBufBlobStream.Create(Field as tblobfield,bmWrite);
  2110. if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
  2111. DataEvent(deFieldChange, Ptrint(Field));
  2112. end;
  2113. end;
  2114. procedure TCustomBufDataset.AddIndex(const AName, AFields : string; AOptions : TIndexOptions; const ADescFields: string = '';
  2115. const ACaseInsFields: string = '');
  2116. begin
  2117. CheckBiDirectional;
  2118. if AFields='' then DatabaseError(SNoIndexFieldNameGiven);
  2119. if FIndexesCount=0 then
  2120. InitDefaultIndexes;
  2121. if active and (FIndexesCount=FMaxIndexesCount) then
  2122. DatabaseError(SMaxIndexes);
  2123. // If not all packets are fetched, you can not sort properly.
  2124. if not active then
  2125. FPacketRecords:=-1;
  2126. InternalAddIndex(AName,AFields,AOptions,ADescFields,ACaseInsFields);
  2127. end;
  2128. procedure TCustomBufDataset.SaveToFile(AFileName: string;
  2129. Format: TDataPacketFormat);
  2130. var AFileStream : TFileStream;
  2131. begin
  2132. if AFileName='' then AFileName := FFileName;
  2133. AFileStream := TFileStream.Create(AFileName,fmCreate);
  2134. try
  2135. SaveToStream(AFileStream, Format);
  2136. finally
  2137. AFileStream.Free;
  2138. end;
  2139. end;
  2140. procedure TCustomBufDataset.SetDatasetPacket(AReader: TDataPacketReader);
  2141. begin
  2142. FDatasetReader := AReader;
  2143. try
  2144. Open;
  2145. finally
  2146. FDatasetReader := nil;
  2147. end;
  2148. end;
  2149. procedure TCustomBufDataset.GetDatasetPacket(AWriter: TDataPacketReader);
  2150. procedure StoreUpdateBuffer(AUpdBuffer : TRecUpdateBuffer; var ARowState: TRowState);
  2151. var AThisRowState : TRowState;
  2152. AStoreUpdBuf : Integer;
  2153. begin
  2154. if AUpdBuffer.UpdateKind = ukModify then
  2155. begin
  2156. AThisRowState := [rsvOriginal];
  2157. ARowState:=[rsvUpdated];
  2158. end
  2159. else if AUpdBuffer.UpdateKind = ukDelete then
  2160. begin
  2161. AStoreUpdBuf:=FCurrentUpdateBuffer;
  2162. if GetRecordUpdateBuffer(AUpdBuffer.BookmarkData,True,False) then
  2163. begin
  2164. repeat
  2165. if FCurrentIndex.CompareBookmarks(@FUpdateBuffer[FCurrentUpdateBuffer].NextBookmarkData, @AUpdBuffer.BookmarkData) then
  2166. StoreUpdateBuffer(FUpdateBuffer[FCurrentUpdateBuffer], ARowState);
  2167. until not GetRecordUpdateBuffer(AUpdBuffer.BookmarkData,True,True)
  2168. end;
  2169. FCurrentUpdateBuffer:=AStoreUpdBuf;
  2170. AThisRowState := [rsvDeleted];
  2171. end
  2172. else // ie: UpdateKind = ukInsert
  2173. ARowState := [rsvInserted];
  2174. FFilterBuffer:=AUpdBuffer.OldValuesBuffer;
  2175. // If the record is inserted or inserted and afterwards deleted then OldValuesBuffer is nil
  2176. if assigned(FFilterBuffer) then
  2177. FDatasetReader.StoreRecord(Self,AThisRowState,FCurrentUpdateBuffer);
  2178. end;
  2179. procedure HandleUpdateBuffersFromRecord(AFirstCall : boolean;ARecBookmark : TBufBookmark; var ARowState: TRowState);
  2180. var StoreUpdBuf1,StoreUpdBuf2 : Integer;
  2181. begin
  2182. if AFirstCall then ARowState:=[];
  2183. if GetRecordUpdateBuffer(ARecBookmark,True,not AFirstCall) then
  2184. begin
  2185. if FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind=ukDelete then
  2186. begin
  2187. StoreUpdBuf1:=FCurrentUpdateBuffer;
  2188. HandleUpdateBuffersFromRecord(False,ARecBookmark,ARowState);
  2189. StoreUpdBuf2:=FCurrentUpdateBuffer;
  2190. FCurrentUpdateBuffer:=StoreUpdBuf1;
  2191. StoreUpdateBuffer(FUpdateBuffer[StoreUpdBuf1], ARowState);
  2192. FCurrentUpdateBuffer:=StoreUpdBuf2;
  2193. end
  2194. else
  2195. begin
  2196. StoreUpdateBuffer(FUpdateBuffer[FCurrentUpdateBuffer], ARowState);
  2197. HandleUpdateBuffersFromRecord(False,ARecBookmark,ARowState);
  2198. end;
  2199. end
  2200. end;
  2201. var ScrollResult : TGetResult;
  2202. StoreDSState : TDataSetState;
  2203. ABookMark : PBufBookmark;
  2204. ATBookmark : TBufBookmark;
  2205. RowState : TRowState;
  2206. begin
  2207. FDatasetReader := AWriter;
  2208. try
  2209. //CheckActive;
  2210. ABookMark:=@ATBookmark;
  2211. FDatasetReader.StoreFieldDefs(FieldDefs);
  2212. StoreDSState:=SetTempState(dsFilter);
  2213. ScrollResult:=FCurrentIndex.ScrollFirst;
  2214. while ScrollResult=grOK do
  2215. begin
  2216. RowState:=[];
  2217. FCurrentIndex.StoreCurrentRecIntoBookmark(ABookmark);
  2218. HandleUpdateBuffersFromRecord(True,ABookmark^,RowState);
  2219. FFilterBuffer:=FCurrentIndex.CurrentBuffer;
  2220. if RowState=[] then
  2221. FDatasetReader.StoreRecord(Self,[])
  2222. else
  2223. FDatasetReader.StoreRecord(Self,RowState,FCurrentUpdateBuffer);
  2224. ScrollResult:=FCurrentIndex.ScrollForward;
  2225. if ScrollResult<>grOK then
  2226. begin
  2227. if getnextpacket>0 then
  2228. ScrollResult := FCurrentIndex.ScrollForward;
  2229. end;
  2230. end;
  2231. // There could be a update-buffer linked to the last (spare) record
  2232. FCurrentIndex.StoreSpareRecIntoBookmark(ABookmark);
  2233. HandleUpdateBuffersFromRecord(True,ABookmark^,RowState);
  2234. RestoreState(StoreDSState);
  2235. FDatasetReader.FinalizeStoreRecords;
  2236. finally
  2237. FDatasetReader := nil;
  2238. end;
  2239. end;
  2240. procedure TCustomBufDataset.LoadFromStream(AStream: TStream; Format: TDataPacketFormat);
  2241. var APacketReaderReg : TDatapacketReaderRegistration;
  2242. APacketReader : TDataPacketReader;
  2243. begin
  2244. CheckBiDirectional;
  2245. if GetRegisterDatapacketReader(AStream,format,APacketReaderReg) then
  2246. APacketReader := APacketReaderReg.ReaderClass.create(AStream)
  2247. else if TFpcBinaryDatapacketReader.RecognizeStream(AStream) then
  2248. begin
  2249. AStream.Seek(0,soFromBeginning);
  2250. APacketReader := TFpcBinaryDatapacketReader.create(AStream)
  2251. end
  2252. else
  2253. DatabaseError(SStreamNotRecognised);
  2254. try
  2255. SetDatasetPacket(APacketReader);
  2256. finally
  2257. APacketReader.Free;
  2258. end;
  2259. end;
  2260. procedure TCustomBufDataset.SaveToStream(AStream: TStream; Format: TDataPacketFormat);
  2261. var APacketReaderReg : TDatapacketReaderRegistration;
  2262. APacketWriter : TDataPacketReader;
  2263. begin
  2264. CheckBiDirectional;
  2265. if GetRegisterDatapacketReader(Nil,format,APacketReaderReg) then
  2266. APacketWriter := APacketReaderReg.ReaderClass.create(AStream)
  2267. else if Format = dfBinary then
  2268. APacketWriter := TFpcBinaryDatapacketReader.create(AStream)
  2269. else
  2270. DatabaseError(SNoReaderClassRegistered);
  2271. try
  2272. GetDatasetPacket(APacketWriter);
  2273. finally
  2274. APacketWriter.Free;
  2275. end;
  2276. end;
  2277. procedure TCustomBufDataset.LoadFromFile(AFileName: string; Format: TDataPacketFormat);
  2278. var AFileStream : TFileStream;
  2279. begin
  2280. if AFileName='' then AFileName := FFileName;
  2281. AFileStream := TFileStream.Create(AFileName,fmOpenRead);
  2282. try
  2283. LoadFromStream(AFileStream, Format);
  2284. finally
  2285. AFileStream.Free;
  2286. end;
  2287. end;
  2288. procedure TCustomBufDataset.CreateDataset;
  2289. begin
  2290. CheckInactive;
  2291. CreateFields;
  2292. end;
  2293. function TCustomBufDataset.BookmarkValid(ABookmark: TBookmark): Boolean;
  2294. begin
  2295. Result:=assigned(FCurrentIndex) and FCurrentIndex.BookmarkValid(ABookmark);
  2296. end;
  2297. function TCustomBufDataset.CompareBookmarks(Bookmark1, Bookmark2: TBookmark
  2298. ): Longint;
  2299. begin
  2300. if Assigned(FCurrentIndex) and FCurrentIndex.CompareBookmarks(Bookmark1,Bookmark2) then
  2301. Result := 0
  2302. else
  2303. Result := -1;
  2304. end;
  2305. procedure TCustomBufDataset.IntLoadFielddefsFromFile;
  2306. begin
  2307. FDatasetReader.LoadFielddefs(FieldDefs);
  2308. if DefaultFields then CreateFields;
  2309. end;
  2310. procedure TCustomBufDataset.IntLoadRecordsFromFile;
  2311. var StoreState : TDataSetState;
  2312. AddRecordBuffer : boolean;
  2313. ARowState : TRowState;
  2314. AUpdOrder : integer;
  2315. x : integer;
  2316. begin
  2317. CheckBiDirectional;
  2318. FDatasetReader.InitLoadRecords;
  2319. StoreState:=SetTempState(dsFilter);
  2320. while FDatasetReader.GetCurrentRecord do
  2321. begin
  2322. ARowState := FDatasetReader.GetRecordRowState(AUpdOrder);
  2323. if rsvOriginal in ARowState then
  2324. begin
  2325. if length(FUpdateBuffer) < (AUpdOrder+1) then
  2326. SetLength(FUpdateBuffer,AUpdOrder+1);
  2327. FCurrentUpdateBuffer:=AUpdOrder;
  2328. FFilterBuffer:=IntAllocRecordBuffer;
  2329. fillchar(FFilterBuffer^,FNullmaskSize,0);
  2330. FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := FFilterBuffer;
  2331. FDatasetReader.RestoreRecord(self);
  2332. FDatasetReader.GotoNextRecord;
  2333. if not FDatasetReader.GetCurrentRecord then
  2334. DatabaseError(SStreamNotRecognised);
  2335. ARowState := FDatasetReader.GetRecordRowState(AUpdOrder);
  2336. if rsvUpdated in ARowState then
  2337. FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind:= ukModify
  2338. else
  2339. DatabaseError(SStreamNotRecognised);
  2340. FFilterBuffer:=FIndexes[0].SpareBuffer;
  2341. FIndexes[0].StoreSpareRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData);
  2342. fillchar(FFilterBuffer^,FNullmaskSize,0);
  2343. FDatasetReader.RestoreRecord(self);
  2344. FIndexes[0].AddRecord;
  2345. inc(FBRecordCount);
  2346. AddRecordBuffer:=False;
  2347. end
  2348. else if rsvDeleted in ARowState then
  2349. begin
  2350. if length(FUpdateBuffer) < (AUpdOrder+1) then
  2351. SetLength(FUpdateBuffer,AUpdOrder+1);
  2352. FCurrentUpdateBuffer:=AUpdOrder;
  2353. FFilterBuffer:=IntAllocRecordBuffer;
  2354. fillchar(FFilterBuffer^,FNullmaskSize,0);
  2355. FUpdateBuffer[FCurrentUpdateBuffer].OldValuesBuffer := FFilterBuffer;
  2356. FDatasetReader.RestoreRecord(self);
  2357. FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind:= ukDelete;
  2358. FIndexes[0].StoreSpareRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData);
  2359. FIndexes[0].AddRecord;
  2360. FIndexes[0].RemoveRecordFromIndex(FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData);
  2361. FIndexes[0].StoreSpareRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].NextBookmarkData);
  2362. for x := FCurrentUpdateBuffer+1 to length(FUpdateBuffer)-1 do
  2363. if Findexes[0].CompareBookmarks(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData,@FUpdateBuffer[x].NextBookmarkData) then
  2364. FIndexes[0].StoreSpareRecIntoBookmark(@FUpdateBuffer[x].NextBookmarkData);
  2365. AddRecordBuffer:=False;
  2366. end
  2367. else
  2368. AddRecordBuffer:=True;
  2369. if AddRecordBuffer then
  2370. begin
  2371. FFilterBuffer:=FIndexes[0].SpareBuffer;
  2372. fillchar(FFilterBuffer^,FNullmaskSize,0);
  2373. FDatasetReader.RestoreRecord(self);
  2374. if rsvInserted in ARowState then
  2375. begin
  2376. if length(FUpdateBuffer) < (AUpdOrder+1) then
  2377. SetLength(FUpdateBuffer,AUpdOrder+1);
  2378. FCurrentUpdateBuffer:=AUpdOrder;
  2379. FUpdateBuffer[FCurrentUpdateBuffer].UpdateKind:= ukInsert;
  2380. FIndexes[0].StoreSpareRecIntoBookmark(@FUpdateBuffer[FCurrentUpdateBuffer].BookmarkData);
  2381. end;
  2382. FIndexes[0].AddRecord;
  2383. inc(FBRecordCount);
  2384. end;
  2385. FDatasetReader.GotoNextRecord;
  2386. end;
  2387. RestoreState(StoreState);
  2388. FIndexes[0].SetToFirstRecord;
  2389. FAllPacketsFetched:=True;
  2390. if assigned(FFileStream) then
  2391. begin
  2392. FreeAndNil(FFileStream);
  2393. FreeAndNil(FDatasetReader);
  2394. end;
  2395. // rebuild indexes
  2396. for x:=1 to FIndexesCount-1 do
  2397. if (x<>1) or (FIndexes[x]=FCurrentIndex) then
  2398. BuildIndex(FIndexes[x]);
  2399. end;
  2400. procedure TCustomBufDataset.InternalAddIndex(const AName, AFields : string; AOptions : TIndexOptions; const ADescFields: string;
  2401. const ACaseInsFields: string);
  2402. var StoreIndNr : Integer;
  2403. begin
  2404. if Active then FetchAll;
  2405. if FIndexesCount>0 then
  2406. StoreIndNr:=FCurrentIndex.IndNr
  2407. else
  2408. StoreIndNr:=0;
  2409. inc(FIndexesCount);
  2410. setlength(FIndexes,FIndexesCount); // This invalidates the currentindex! -> not anymore
  2411. FCurrentIndex:=FIndexes[StoreIndNr];
  2412. if IsUniDirectional then
  2413. FIndexes[FIndexesCount-1] := TUniDirectionalBufIndex.Create(self)
  2414. else
  2415. FIndexes[FIndexesCount-1] := TDoubleLinkedBufIndex.Create(self);
  2416. // FIndexes[FIndexesCount-1] := TArrayBufIndex.Create(self);
  2417. FIndexes[FIndexesCount-1].InitialiseIndex;
  2418. with (FIndexes[FIndexesCount-1] as TBufIndex) do
  2419. begin
  2420. Name:=AName;
  2421. FieldsName:=AFields;
  2422. DescFields:=ADescFields;
  2423. CaseinsFields:=ACaseInsFields;
  2424. Options:=AOptions;
  2425. IndNr:=FIndexesCount-1;
  2426. end;
  2427. if Active then
  2428. begin
  2429. FIndexes[FIndexesCount-1].InitialiseSpareRecord(IntAllocRecordBuffer);
  2430. BuildIndex(FIndexes[FIndexesCount-1]);
  2431. end
  2432. else if FIndexesCount>FMaxIndexesCount then
  2433. FMaxIndexesCount := FIndexesCount;
  2434. end;
  2435. procedure TCustomBufDataset.DoFilterRecord(out Acceptable: Boolean);
  2436. begin
  2437. Acceptable := true;
  2438. // check user filter
  2439. if Assigned(OnFilterRecord) then
  2440. OnFilterRecord(Self, Acceptable);
  2441. // check filtertext
  2442. if Acceptable and (Length(Filter) > 0) then
  2443. Acceptable := Boolean((FParser.ExtractFromBuffer(GetCurrentBuffer))^);
  2444. end;
  2445. procedure TCustomBufDataset.SetFilterText(const Value: String);
  2446. begin
  2447. if Value = Filter then
  2448. exit;
  2449. // parse
  2450. ParseFilter(Value);
  2451. // call dataset method
  2452. inherited;
  2453. // refilter dataset if filtered
  2454. if IsCursorOpen and Filtered then Resync([]);
  2455. end;
  2456. procedure TCustomBufDataset.SetFiltered(Value: Boolean); {override;}
  2457. begin
  2458. if Value = Filtered then
  2459. exit;
  2460. // pass on to ancestor
  2461. inherited;
  2462. // only refresh if active
  2463. if IsCursorOpen then
  2464. Resync([]);
  2465. end;
  2466. procedure TCustomBufDataset.InternalRefresh;
  2467. var StoreDefaultFields: boolean;
  2468. begin
  2469. StoreDefaultFields:=DefaultFields;
  2470. SetDefaultFields(False);
  2471. FreeFieldBuffers;
  2472. ClearBuffers;
  2473. InternalClose;
  2474. BeforeRefreshOpenCursor;
  2475. InternalOpen;
  2476. SetDefaultFields(StoreDefaultFields);
  2477. end;
  2478. procedure TCustomBufDataset.BeforeRefreshOpenCursor;
  2479. begin
  2480. // Do nothing
  2481. end;
  2482. procedure TCustomBufDataset.DataEvent(Event: TDataEvent; Info: Ptrint);
  2483. begin
  2484. if Event = deUpdateState then
  2485. // Save DataSet.State set by DataSet.SetState (filter out State set by DataSet.SetTempState)
  2486. FSavedState := State;
  2487. inherited;
  2488. end;
  2489. function TCustomBufDataset.Fetch: boolean;
  2490. begin
  2491. // Empty procedure to make it possible to use TCustomBufDataset as a memory dataset
  2492. Result := False;
  2493. end;
  2494. function TCustomBufDataset.LoadField(FieldDef: TFieldDef; buffer: pointer; out
  2495. CreateBlob: boolean): boolean;
  2496. begin
  2497. // Empty procedure to make it possible to use TCustomBufDataset as a memory dataset
  2498. CreateBlob := False;
  2499. Result := False;
  2500. end;
  2501. function TCustomBufDataset.IsReadFromPacket: Boolean;
  2502. begin
  2503. Result := (FDatasetReader<>nil) or (FFileName<>'') or FReadFromFile;
  2504. end;
  2505. procedure TCustomBufDataset.ParseFilter(const AFilter: string);
  2506. begin
  2507. // parser created?
  2508. if Length(AFilter) > 0 then
  2509. begin
  2510. if (FParser = nil) and IsCursorOpen then
  2511. begin
  2512. FParser := TBufDatasetParser.Create(Self);
  2513. end;
  2514. // have a parser now?
  2515. if FParser <> nil then
  2516. begin
  2517. // set options
  2518. FParser.PartialMatch := not (foNoPartialCompare in FilterOptions);
  2519. FParser.CaseInsensitive := foCaseInsensitive in FilterOptions;
  2520. // parse expression
  2521. FParser.ParseExpression(AFilter);
  2522. end;
  2523. end;
  2524. end;
  2525. function TArrayBufIndex.GetRecordFromBookmark(ABookMark: TBufBookmark) : integer;
  2526. begin
  2527. // ABookmark.BookMarkBuf is nil if SetRecNo calls GotoBookmark
  2528. if (ABookmark.BookmarkData<>nil) and (FRecordArray[ABookmark.BookmarkInt]<>ABookmark.BookmarkData) then
  2529. begin
  2530. // Start searching two records before the expected record
  2531. if ABookmark.BookmarkInt > 2 then
  2532. Result := ABookmark.BookmarkInt-2
  2533. else
  2534. Result := 0;
  2535. while (Result<FLastRecInd) do
  2536. begin
  2537. if (FRecordArray[Result] = ABookmark.BookmarkData) then exit;
  2538. inc(Result);
  2539. end;
  2540. Result:=0;
  2541. while (Result<ABookmark.BookmarkInt) do
  2542. begin
  2543. if (FRecordArray[Result] = ABookmark.BookmarkData) then exit;
  2544. inc(Result);
  2545. end;
  2546. DatabaseError(SInvalidBookmark)
  2547. end
  2548. else
  2549. Result := ABookmark.BookmarkInt;
  2550. end;
  2551. Function TCustomBufDataset.Locate(const KeyFields: string; const KeyValues: Variant; options: TLocateOptions) : boolean;
  2552. var CurrLinkItem : PBufRecLinkItem;
  2553. bm : TBufBookmark;
  2554. SearchFields : TList;
  2555. FieldsAmount : Integer;
  2556. DBCompareStruct : TDBCompareStruct;
  2557. FieldNr : Integer;
  2558. StoreDSState : TDataSetState;
  2559. FilterBuffer : TRecordBuffer;
  2560. FiltAcceptable : boolean;
  2561. begin
  2562. // Call inherited to make sure the dataset is bi-directional
  2563. Result := inherited;
  2564. CheckActive;
  2565. if IsEmpty then exit;
  2566. // Build the DBCompare structure
  2567. SearchFields := TList.Create;
  2568. try
  2569. GetFieldList(SearchFields,KeyFields);
  2570. FieldsAmount:=SearchFields.Count;
  2571. if FieldsAmount=0 then exit;
  2572. SetLength(DBCompareStruct,FieldsAmount);
  2573. for FieldNr:=0 to FieldsAmount-1 do
  2574. begin
  2575. ProcessFieldCompareStruct(TField(SearchFields[FieldNr]),DBCompareStruct[FieldNr]);
  2576. DBCompareStruct[FieldNr].Options:=options;
  2577. end;
  2578. finally
  2579. SearchFields.Free;
  2580. end;
  2581. // Set The filter-buffer
  2582. StoreDSState:=SetTempState(dsFilter);
  2583. FFilterBuffer:=FCurrentIndex.SpareBuffer;
  2584. SetFieldValues(keyfields,KeyValues);
  2585. CurrLinkItem := (FCurrentIndex as TDoubleLinkedBufIndex).FFirstRecBuf;
  2586. FilterBuffer:=IntAllocRecordBuffer;
  2587. move((FCurrentIndex as TDoubleLinkedBufIndex).FLastRecBuf^,FilterBuffer^,FRecordsize+sizeof(TBufRecLinkItem)*FMaxIndexesCount);
  2588. // Iterate through the records until a match is found
  2589. while (CurrLinkItem <> (FCurrentIndex as TDoubleLinkedBufIndex).FLastRecBuf) do
  2590. begin
  2591. if (IndexCompareRecords(FilterBuffer,CurrLinkItem,DBCompareStruct) = 0) then
  2592. begin
  2593. if Filtered then
  2594. begin
  2595. FFilterBuffer:=pointer(CurrLinkItem)+(sizeof(TBufRecLinkItem)*MaxIndexesCount);
  2596. // The dataset-state is still dsFilter at this point, so we don't have to set it.
  2597. DoFilterRecord(FiltAcceptable);
  2598. if FiltAcceptable then
  2599. begin
  2600. Result := True;
  2601. break;
  2602. end;
  2603. end
  2604. else
  2605. begin
  2606. Result := True;
  2607. break;
  2608. end;
  2609. end;
  2610. CurrLinkItem := CurrLinkItem[(FCurrentIndex as TDoubleLinkedBufIndex).IndNr].next;
  2611. if CurrLinkItem = (FCurrentIndex as TDoubleLinkedBufIndex).FLastRecBuf then
  2612. getnextpacket;
  2613. end;
  2614. RestoreState(StoreDSState);
  2615. FreeRecordBuffer(FilterBuffer);
  2616. // If a match is found, jump to the found record
  2617. if Result then
  2618. begin
  2619. bm.BookmarkData := CurrLinkItem;
  2620. bm.BookmarkFlag := bfCurrent;
  2621. GotoBookmark(@bm);
  2622. end;
  2623. end;
  2624. function TCustomBufDataset.Lookup(const KeyFields: string;
  2625. const KeyValues: Variant; const ResultFields: string): Variant;
  2626. var
  2627. bm:TBookmark;
  2628. begin
  2629. result:=Null;
  2630. bm:=GetBookmark;
  2631. DisableControls;
  2632. try
  2633. if Locate(KeyFields,KeyValues,[]) then
  2634. begin
  2635. // CalculateFields(ActiveBuffer); // not needed, done by Locate more than once
  2636. result:=FieldValues[ResultFields];
  2637. end;
  2638. GotoBookmark(bm);
  2639. FreeBookmark(bm);
  2640. finally
  2641. EnableControls;
  2642. end;
  2643. end;
  2644. { TArrayBufIndex }
  2645. function TArrayBufIndex.GetBookmarkSize: integer;
  2646. begin
  2647. Result:=Sizeof(TBufBookmark);
  2648. end;
  2649. function TArrayBufIndex.GetCurrentBuffer: Pointer;
  2650. begin
  2651. Result:=TRecordBuffer(FRecordArray[FCurrentRecInd]);
  2652. end;
  2653. function TArrayBufIndex.GetCurrentRecord: TRecordBuffer;
  2654. begin
  2655. Result:=GetCurrentBuffer;
  2656. end;
  2657. function TArrayBufIndex.GetIsInitialized: boolean;
  2658. begin
  2659. Result:=Length(FRecordArray)>0;
  2660. end;
  2661. function TArrayBufIndex.GetSpareBuffer: TRecordBuffer;
  2662. begin
  2663. if FLastRecInd>-1 then
  2664. Result:= TRecordBuffer(FRecordArray[FLastRecInd])
  2665. else
  2666. Result := nil;
  2667. end;
  2668. function TArrayBufIndex.GetSpareRecord: TRecordBuffer;
  2669. begin
  2670. Result := GetSpareBuffer;
  2671. end;
  2672. constructor TArrayBufIndex.Create(const ADataset: TCustomBufDataset);
  2673. begin
  2674. Inherited create(ADataset);
  2675. FInitialBuffers:=10000;
  2676. FGrowBuffer:=1000;
  2677. end;
  2678. function TArrayBufIndex.ScrollBackward: TGetResult;
  2679. begin
  2680. if FCurrentRecInd>0 then
  2681. begin
  2682. dec(FCurrentRecInd);
  2683. Result := grOK;
  2684. end
  2685. else
  2686. Result := grBOF;
  2687. end;
  2688. function TArrayBufIndex.ScrollForward: TGetResult;
  2689. begin
  2690. if FCurrentRecInd = FLastRecInd-1 then
  2691. result := grEOF
  2692. else
  2693. begin
  2694. Result:=grOK;
  2695. inc(FCurrentRecInd);
  2696. end;
  2697. end;
  2698. function TArrayBufIndex.GetCurrent: TGetResult;
  2699. begin
  2700. if FLastRecInd=0 then
  2701. Result := grError
  2702. else
  2703. begin
  2704. Result := grOK;
  2705. if FCurrentRecInd = FLastRecInd then
  2706. dec(FCurrentRecInd);
  2707. end;
  2708. end;
  2709. function TArrayBufIndex.ScrollFirst: TGetResult;
  2710. begin
  2711. FCurrentRecInd:=0;
  2712. if (FCurrentRecInd = FLastRecInd) then
  2713. result := grEOF
  2714. else
  2715. result := grOk;
  2716. end;
  2717. procedure TArrayBufIndex.ScrollLast;
  2718. begin
  2719. FCurrentRecInd:=FLastRecInd;
  2720. end;
  2721. procedure TArrayBufIndex.SetToFirstRecord;
  2722. begin
  2723. // if FCurrentRecBuf = FLastRecBuf then the dataset is just opened and empty
  2724. // in which case InternalFirst should do nothing (bug 7211)
  2725. if FCurrentRecInd <> FLastRecInd then
  2726. FCurrentRecInd := -1;
  2727. end;
  2728. procedure TArrayBufIndex.SetToLastRecord;
  2729. begin
  2730. if FLastRecInd <> 0 then FCurrentRecInd := FLastRecInd;
  2731. end;
  2732. procedure TArrayBufIndex.StoreCurrentRecord;
  2733. begin
  2734. FStoredRecBuf := FCurrentRecInd;
  2735. end;
  2736. procedure TArrayBufIndex.RestoreCurrentRecord;
  2737. begin
  2738. FCurrentRecInd := FStoredRecBuf;
  2739. end;
  2740. function TArrayBufIndex.CanScrollForward: Boolean;
  2741. begin
  2742. Result := (FCurrentRecInd < FLastRecInd-1);
  2743. end;
  2744. procedure TArrayBufIndex.DoScrollForward;
  2745. begin
  2746. inc(FCurrentRecInd);
  2747. end;
  2748. procedure TArrayBufIndex.StoreCurrentRecIntoBookmark(const ABookmark: PBufBookmark);
  2749. begin
  2750. with ABookmark^ do
  2751. begin
  2752. BookmarkInt := FCurrentRecInd;
  2753. BookmarkData := FRecordArray[FCurrentRecInd];
  2754. end;
  2755. end;
  2756. procedure TArrayBufIndex.StoreSpareRecIntoBookmark(const ABookmark: PBufBookmark
  2757. );
  2758. begin
  2759. with ABookmark^ do
  2760. begin
  2761. BookmarkInt := FLastRecInd;
  2762. BookmarkData := FRecordArray[FLastRecInd];
  2763. end;
  2764. end;
  2765. procedure TArrayBufIndex.GotoBookmark(const ABookmark : PBufBookmark);
  2766. begin
  2767. FCurrentRecInd:=GetRecordFromBookmark(ABookmark^);
  2768. end;
  2769. procedure TArrayBufIndex.InitialiseIndex;
  2770. begin
  2771. // FRecordArray:=nil;
  2772. setlength(FRecordArray,FInitialBuffers);
  2773. FCurrentRecInd:=-1;
  2774. FLastRecInd:=-1;
  2775. end;
  2776. procedure TArrayBufIndex.InitialiseSpareRecord(const ASpareRecord: TRecordBuffer);
  2777. begin
  2778. FLastRecInd := 0;
  2779. // FCurrentRecInd := 0;
  2780. FRecordArray[0] := ASpareRecord;
  2781. end;
  2782. procedure TArrayBufIndex.ReleaseSpareRecord;
  2783. begin
  2784. SetLength(FRecordArray,FInitialBuffers);
  2785. end;
  2786. function TArrayBufIndex.GetRecNo(const ABookmark: PBufBookmark): integer;
  2787. begin
  2788. Result := GetRecordFromBookmark(ABookmark^)+1;
  2789. end;
  2790. procedure TArrayBufIndex.RemoveRecordFromIndex(const ABookmark : TBufBookmark);
  2791. var ARecordInd : integer;
  2792. begin
  2793. ARecordInd:=GetRecordFromBookmark(ABookmark);
  2794. Move(FRecordArray[ARecordInd+1],FRecordArray[ARecordInd],sizeof(Pointer)*(FLastRecInd-ARecordInd));
  2795. dec(FLastRecInd);
  2796. end;
  2797. procedure TArrayBufIndex.InsertRecordBeforeCurrentRecord(const ARecord: TRecordBuffer);
  2798. begin
  2799. inc(FLastRecInd);
  2800. if FLastRecInd >= length(FRecordArray) then
  2801. SetLength(FRecordArray,length(FRecordArray)+FGrowBuffer);
  2802. Move(FRecordArray[FCurrentRecInd],FRecordArray[FCurrentRecInd+1],sizeof(Pointer)*(FLastRecInd-FCurrentRecInd));
  2803. FRecordArray[FCurrentRecInd]:=ARecord;
  2804. inc(FCurrentRecInd);
  2805. end;
  2806. procedure TArrayBufIndex.BeginUpdate;
  2807. begin
  2808. // inherited BeginUpdate;
  2809. end;
  2810. procedure TArrayBufIndex.AddRecord;
  2811. var ARecord: TRecordBuffer;
  2812. begin
  2813. ARecord := FDataset.IntAllocRecordBuffer;
  2814. inc(FLastRecInd);
  2815. if FLastRecInd >= length(FRecordArray) then
  2816. SetLength(FRecordArray,length(FRecordArray)+FGrowBuffer);
  2817. FRecordArray[FLastRecInd]:=ARecord;
  2818. end;
  2819. procedure TArrayBufIndex.EndUpdate;
  2820. begin
  2821. // inherited EndUpdate;
  2822. end;
  2823. { TDataPacketReader }
  2824. class function TDataPacketReader.RowStateToByte(const ARowState: TRowState
  2825. ): byte;
  2826. var RowStateInt : Byte;
  2827. begin
  2828. RowStateInt:=0;
  2829. if rsvOriginal in ARowState then RowStateInt := RowStateInt+1;
  2830. if rsvDeleted in ARowState then RowStateInt := RowStateInt+2;
  2831. if rsvInserted in ARowState then RowStateInt := RowStateInt+4;
  2832. if rsvUpdated in ARowState then RowStateInt := RowStateInt+8;
  2833. Result := RowStateInt;
  2834. end;
  2835. class function TDataPacketReader.ByteToRowState(const AByte: Byte): TRowState;
  2836. begin
  2837. result := [];
  2838. if (AByte and 1)=1 then Result := Result+[rsvOriginal];
  2839. if (AByte and 2)=2 then Result := Result+[rsvDeleted];
  2840. if (AByte and 4)=4 then Result := Result+[rsvInserted];
  2841. if (AByte and 8)=8 then Result := Result+[rsvUpdated];
  2842. end;
  2843. constructor TDataPacketReader.create(AStream: TStream);
  2844. begin
  2845. FStream := AStream;
  2846. end;
  2847. { TFpcBinaryDatapacketReader }
  2848. const FpcBinaryIdent = 'BinBufDataset';
  2849. procedure TFpcBinaryDatapacketReader.LoadFieldDefs(AFieldDefs: TFieldDefs);
  2850. var FldCount : word;
  2851. i : integer;
  2852. begin
  2853. if not RecognizeStream(Stream) then
  2854. DatabaseError(SStreamNotRecognised);
  2855. FldCount:=Stream.ReadWord;
  2856. AFieldDefs.Clear;
  2857. for i := 0 to FldCount -1 do with TFieldDef.create(AFieldDefs) do
  2858. begin
  2859. Name := Stream.ReadAnsiString;
  2860. Displayname := Stream.ReadAnsiString;
  2861. Size := Stream.ReadWord;
  2862. DataType := TFieldType(Stream.ReadWord);
  2863. if Stream.ReadByte = 1 then
  2864. Attributes := Attributes + [faReadonly];
  2865. end;
  2866. end;
  2867. procedure TFpcBinaryDatapacketReader.StoreFieldDefs(AFieldDefs: TFieldDefs);
  2868. var i : integer;
  2869. begin
  2870. Stream.Write(FpcBinaryIdent[1],length(FpcBinaryIdent));
  2871. Stream.WriteWord(AFieldDefs.Count);
  2872. for i := 0 to AFieldDefs.Count -1 do with AFieldDefs[i] do
  2873. begin
  2874. Stream.WriteAnsiString(Name);
  2875. Stream.WriteAnsiString(DisplayName);
  2876. Stream.WriteWord(size);
  2877. Stream.WriteWord(ord(DataType));
  2878. if faReadonly in Attributes then
  2879. Stream.WriteByte(1)
  2880. else
  2881. Stream.WriteByte(0);
  2882. end;
  2883. end;
  2884. function TFpcBinaryDatapacketReader.GetRecordRowState(out AUpdOrder : Integer) : TRowState;
  2885. var Buf : byte;
  2886. begin
  2887. Stream.Read(Buf,1);
  2888. Result := ByteToRowState(Buf);
  2889. if Result<>[] then
  2890. Stream.ReadBuffer(AUpdOrder,sizeof(integer))
  2891. else
  2892. AUpdOrder := 0;
  2893. end;
  2894. procedure TFpcBinaryDatapacketReader.FinalizeStoreRecords;
  2895. begin
  2896. // Do nothing
  2897. end;
  2898. function TFpcBinaryDatapacketReader.GetCurrentRecord: boolean;
  2899. var Buf : byte;
  2900. begin
  2901. Result := (Stream.Read(Buf,1)=1) and (Buf=$fe);
  2902. end;
  2903. procedure TFpcBinaryDatapacketReader.GotoNextRecord;
  2904. begin
  2905. // Do Nothing
  2906. end;
  2907. procedure TFpcBinaryDatapacketReader.InitLoadRecords;
  2908. begin
  2909. // SetLength(AChangeLog,0);
  2910. end;
  2911. procedure TFpcBinaryDatapacketReader.RestoreRecord(ADataset: TCustomBufDataset);
  2912. begin
  2913. Stream.ReadBuffer(ADataset.GetCurrentBuffer^,ADataset.FRecordSize);
  2914. end;
  2915. procedure TFpcBinaryDatapacketReader.StoreRecord(ADataset: TCustomBufDataset;
  2916. ARowState: TRowState; AUpdOrder : integer);
  2917. begin
  2918. // Ugly because private members of ADataset are used...
  2919. Stream.WriteByte($fe);
  2920. Stream.WriteByte(RowStateToByte(ARowState));
  2921. if ARowState<>[] then
  2922. Stream.WriteBuffer(AUpdOrder,sizeof(integer));
  2923. Stream.WriteBuffer(ADataset.GetCurrentBuffer^,ADataset.FRecordSize);
  2924. end;
  2925. class function TFpcBinaryDatapacketReader.RecognizeStream(AStream: TStream
  2926. ): boolean;
  2927. var s : string;
  2928. len : integer;
  2929. begin
  2930. Len := length(FpcBinaryIdent);
  2931. setlength(s,len);
  2932. if (AStream.Read (s[1],len) = len)
  2933. and (s=FpcBinaryIdent) then
  2934. Result := True
  2935. else
  2936. Result := False;
  2937. end;
  2938. { TUniDirectionalBufIndex }
  2939. function TUniDirectionalBufIndex.GetBookmarkSize: integer;
  2940. begin
  2941. // In principle there are no bookmarks, and the size should be 0.
  2942. // But there is quite some code in TCustomBufDataset that relies on
  2943. // an existing bookmark of the TBufBookmark type.
  2944. // This code could be moved to the TBufIndex but that would make things
  2945. // more complicated and probably slower. So use a 'fake' bookmark of
  2946. // size TBufBookmark.
  2947. // When there are other TBufIndexes which also need special bookmark-code
  2948. // this can be adapted.
  2949. Result:=sizeof(TBufBookmark);
  2950. end;
  2951. function TUniDirectionalBufIndex.GetCurrentBuffer: Pointer;
  2952. begin
  2953. result := FSPareBuffer;
  2954. end;
  2955. function TUniDirectionalBufIndex.GetCurrentRecord: TRecordBuffer;
  2956. begin
  2957. // Result:=inherited GetCurrentRecord;
  2958. end;
  2959. function TUniDirectionalBufIndex.GetIsInitialized: boolean;
  2960. begin
  2961. Result := Assigned(FSPareBuffer);
  2962. end;
  2963. function TUniDirectionalBufIndex.GetSpareBuffer: TRecordBuffer;
  2964. begin
  2965. result := FSPareBuffer;
  2966. end;
  2967. function TUniDirectionalBufIndex.GetSpareRecord: TRecordBuffer;
  2968. begin
  2969. result := FSPareBuffer;
  2970. end;
  2971. function TUniDirectionalBufIndex.ScrollBackward: TGetResult;
  2972. begin
  2973. result := grError;
  2974. end;
  2975. function TUniDirectionalBufIndex.ScrollForward: TGetResult;
  2976. begin
  2977. result := grOk;
  2978. end;
  2979. function TUniDirectionalBufIndex.GetCurrent: TGetResult;
  2980. begin
  2981. result := grOk;
  2982. end;
  2983. function TUniDirectionalBufIndex.ScrollFirst: TGetResult;
  2984. begin
  2985. Result:=grError;
  2986. end;
  2987. procedure TUniDirectionalBufIndex.ScrollLast;
  2988. begin
  2989. DatabaseError(SUniDirectional);
  2990. end;
  2991. procedure TUniDirectionalBufIndex.SetToFirstRecord;
  2992. begin
  2993. DatabaseError(SUniDirectional);
  2994. end;
  2995. procedure TUniDirectionalBufIndex.SetToLastRecord;
  2996. begin
  2997. DatabaseError(SUniDirectional);
  2998. end;
  2999. procedure TUniDirectionalBufIndex.StoreCurrentRecord;
  3000. begin
  3001. DatabaseError(SUniDirectional);
  3002. end;
  3003. procedure TUniDirectionalBufIndex.RestoreCurrentRecord;
  3004. begin
  3005. DatabaseError(SUniDirectional);
  3006. end;
  3007. function TUniDirectionalBufIndex.CanScrollForward: Boolean;
  3008. begin
  3009. // should return true if a next record is already fetched
  3010. result := false;
  3011. end;
  3012. procedure TUniDirectionalBufIndex.DoScrollForward;
  3013. begin
  3014. // do nothing
  3015. end;
  3016. procedure TUniDirectionalBufIndex.StoreCurrentRecIntoBookmark(const ABookmark: PBufBookmark);
  3017. begin
  3018. // do nothing
  3019. end;
  3020. procedure TUniDirectionalBufIndex.StoreSpareRecIntoBookmark(const ABookmark: PBufBookmark);
  3021. begin
  3022. // do nothing
  3023. end;
  3024. procedure TUniDirectionalBufIndex.GotoBookmark(const ABookmark: PBufBookmark);
  3025. begin
  3026. DatabaseError(SUniDirectional);
  3027. end;
  3028. procedure TUniDirectionalBufIndex.InitialiseIndex;
  3029. begin
  3030. // do nothing
  3031. end;
  3032. procedure TUniDirectionalBufIndex.InitialiseSpareRecord(const ASpareRecord: TRecordBuffer);
  3033. begin
  3034. FSPareBuffer:=ASpareRecord;
  3035. end;
  3036. procedure TUniDirectionalBufIndex.ReleaseSpareRecord;
  3037. begin
  3038. FSPareBuffer:=nil;
  3039. end;
  3040. procedure TUniDirectionalBufIndex.RemoveRecordFromIndex(const ABookmark: TBufBookmark);
  3041. begin
  3042. DatabaseError(SUniDirectional);
  3043. end;
  3044. function TUniDirectionalBufIndex.GetRecNo(const ABookmark: PBufBookmark): integer;
  3045. begin
  3046. result := -1;
  3047. end;
  3048. procedure TUniDirectionalBufIndex.BeginUpdate;
  3049. begin
  3050. // Do nothing
  3051. end;
  3052. procedure TUniDirectionalBufIndex.AddRecord;
  3053. begin
  3054. // Do nothing
  3055. end;
  3056. procedure TUniDirectionalBufIndex.InsertRecordBeforeCurrentRecord(const ARecord: TRecordBuffer);
  3057. begin
  3058. // Do nothing
  3059. end;
  3060. procedure TUniDirectionalBufIndex.EndUpdate;
  3061. begin
  3062. // Do nothing
  3063. end;
  3064. initialization
  3065. setlength(RegisteredDatapacketReaders,0);
  3066. finalization
  3067. setlength(RegisteredDatapacketReaders,0);
  3068. end.