bufdataset.pas 126 KB

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