bufdataset.pas 119 KB

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