bufdataset.pas 136 KB

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