bufdataset.pas 137 KB

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