bufdataset.pas 106 KB

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