bufdataset.pas 115 KB

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