bufdataset.pas 108 KB

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