DBINDXES.LST 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103
  1. Listing:
  2. 1 IMPLEMENTATION MODULE DBIndxes;
  3. 2 (*# check(overflow=>off) *)
  4. 3 (*/NOCHECK O *)
  5. 4 (*
  6. 5 * ModBase
  7. 6 * Release 3.0
  8. 7 * (c) Copyright 1986 - 1990 Donald G. Fletcher
  9. 8 * (c) Copyright 1986 - 1991 PMI
  10. 9 Copyright 1988 - 1991 John McMonagle
  11. 10 * P.O. Box 8402
  12. 11 * Green Bay Wi 53308
  13. 12 * All Rights Reserved
  14. 13 *)
  15. 14
  16. 15
  17. 16 (*
  18. 17 - DBIndex
  19. 18 - Bug in CloseIndex fixed April 2, 1987
  20. 19 - DeleteEntry rewritten April 2, 1987
  21. 20 - CloseIndex does not write its rootnode unless ndx^.open is TRUE
  22. 21 - Most FOR loops have been rewritten to use Move or ShiftArrayRight
  23. 22 - September 14, 1987 - Rewritten with LONGINT for Logitech 3.0
  24. 23 *)
  25. 24 (*System modules*)
  26. 25 FROM SYSTEM IMPORT ADR,ADDRESS,SIZE,BYTE;
  27. 26 FROM M2Strings IMPORT Assign,CompareStr, Copy,Length,Concat;
  28. 27 (*PMI modules*)
  29. 28 FROM LowLevel IMPORT Move, Fill, ShiftArrayRight,Address8086,
  30. 29 BitwiseAnd,ShiftLeft;
  31. 30 IMPORT StringIO; (*from Repertoire*)
  32. 31 IMPORT HandleIO,FAPI; (*from Repertoire*)
  33. 32 FROM Numbers IMPORT Max;
  34. 33 FROM StrEdit IMPORT CrunchBlanks,CAPstr,Append;
  35. 34 FROM PosUtils IMPORT Equal;
  36. 35 FROM NumTypes IMPORT Real8;
  37. 36 (*ModBase modules*)
  38. 37 FROM ErrorManager IMPORT WARN;
  39. 38 FROM StrConv IMPORT StrToReal;
  40. 39 FROM ModBase3 IMPORT DBFile, ReadDBRec, GetField, SetDBBuffer,
  41. 40 UpDateIndexes,SetRecordMode,OpenDBF,Appending,SetIndexList,
  42. 41 IndexList,NumberRecords,FieldList,BufferSize,PosOfField,Record,
  43. 42 DBFieldPtr,Deleted;
  44. 43 FROM VStorage IMPORT
  45. 44 DosAlloc, DosDealloc,DosAvail;
  46. 45 (* IMPORT ChkInd; *)
  47. 46 (*key numbering convention node[0] contains the number of keys but
  48. 47 getkey etc. the first one is 1 not 0. *)
  49. 48 IMPORT Locks,ModBase3;
  50. ***** ^ duplicate identifier
  51. 49 PROCEDURE DEALLOCATE(VAR loc:ADDRESS;size:CARDINAL);
  52. 50 BEGIN
  53. 51 DosDealloc(loc,size);
  54. ***** ^ not supported yet
  55. ***** ^ not supported yet
  56. ***** ^ not supported yet
  57. 52 END DEALLOCATE;
  58. ***** ^ not supported yet
  59. 53
  60. 54 PROCEDURE ALLOCATE(VAR loc:ADDRESS;size:CARDINAL);
  61. 55 BEGIN
  62. 56 DosAlloc(loc,size);
  63. ***** ^ not supported yet
  64. ***** ^ not supported yet
  65. ***** ^ not supported yet
  66. 57 END ALLOCATE;
  67. ***** ^ not supported yet
  68. 58
  69. 59 CONST
  70. 60 FirstKey = 0; (* the number of the first key in a node *)
  71. 61 MaxKey = 128;
  72. 62 RecNumLen = 4;
  73. 63 NodeSize = 512;
  74. 64 IndexNameLength = 80;
  75. 65 MaxField = 128;
  76. 66 MaxDepth = 24;
  77. 67 FirstNode = 0;
  78. 68 RootNodePtrPos = 4;
  79. 69 NextFreeNodePtrPos = 8;
  80. 70 KeyLenPos = 12;
  81. 71 KeyEntPos = 14;
  82. 72 KeyTypePos = 22;
  83. 73 KeyExpPos = 24;
  84. 74 DepthPosition = 256;
  85. 75 InitCode =56317;
  86. 76 Bins=128;
  87. 77
  88. 78 TYPE
  89. 79 HeaderNodeType=
  90. 80 RECORD
  91. 81 rootptr,
  92. 82 nextfreenode,
  93. 83 FreeList :LONGINT; (* this may not be true dbase compatable *)
  94. 84 keylength,
  95. 85 keyspernode:CARDINAL;
  96. 86 NumType,fill:BOOLEAN;
  97. 87 entrylength:CARDINAL;
  98. 88 Flag,
  99. 89 fill2:CARDINAL;
  100. 90 KeyExpression:ARRAY[0..487] OF CHAR;
  101. ***** ^ not supported yet
  102. ***** ^ not supported yet
  103. 91 END (* record *);
  104. ***** ^ not supported yet
  105. 92
  106. 93 NodeType = ARRAY [0..NodeSize-1] OF CHAR;
  107. ***** ^ not supported yet
  108. ***** ^ not supported yet
  109. 94
  110. 95 IndexBuffer = POINTER TO NodeBuffType;
  111. ***** ^ undeclared identifier
  112. 96
  113. 97 NodeBuffType =
  114. 98 RECORD
  115. 99 node: NodeType;
  116. 100 (* clean:CARDINAL; diag to test for overwriting node *)
  117. 101 number: LONGINT;
  118. 102 next, prev,NHash,PHash: IndexBuffer;
  119. 103 Lock,NeedToWrite:BOOLEAN;
  120. 104 END;
  121. ***** ^ not supported yet
  122. 105
  123. 106 KeyPosType = RECORD
  124. 107 buffer: IndexBuffer ;
  125. 108 keynum : CARDINAL;
  126. 109 END;
  127. ***** ^ not supported yet
  128. 110
  129. 111 Route = ARRAY [0..MaxDepth] OF KeyPosType;
  130. ***** ^ not supported yet
  131. ***** ^ not supported yet
  132. 112
  133. 113 EntryType =
  134. 114 RECORD
  135. 115 lowernode: LONGINT;
  136. 116 recordnum: LONGINT;
  137. 117 value : ARRAY [0..MaxKey] OF CHAR;
  138. ***** ^ not supported yet
  139. ***** ^ not supported yet
  140. 118 END;
  141. ***** ^ not supported yet
  142. 119
  143. 120 KeyPointer=POINTER TO EntryType;
  144. ***** ^ not supported yet
  145. 121
  146. 122 RealEntry =
  147. 123 RECORD
  148. 124 lowernode: LONGINT;
  149. 125 recordnum: LONGINT;
  150. 126 key:Real8;
  151. 127 END;
  152. ***** ^ not supported yet
  153. 128
  154. 129 RealKeyPointer=POINTER TO RealEntry;
  155. ***** ^ not supported yet
  156. 130
  157. 131 CompareType=(LT,EQ,GT);
  158. 132
  159. 133 CompareProc= PROCEDURE( ADDRESS,ADDRESS,CARDINAL): CompareType;
  160. ***** ^ not supported yet
  161. ***** ^ not supported yet
  162. ***** ^ not supported yet
  163. ***** ^ not supported yet
  164. ***** ^ not supported yet
  165. 134
  166. 135
  167. 136 DBIndex= POINTER TO IndexRec;
  168. ***** ^ undeclared identifier
  169. 137 IndexRec =
  170. 138 RECORD
  171. 139 name: ARRAY [1..IndexNameLength] OF CHAR;
  172. ***** ^ not supported yet
  173. ***** ^ not supported yet
  174. 140 f: CARDINAL; (* this is the file handle *)
  175. 141 Locked:CARDINAL; (* indicates file is locked *)
  176. 142 includedeleted,
  177. 143 Exclusive, (* indicates file locking not needed *)
  178. 144 Changed,
  179. 145 open: BOOLEAN;
  180. 146 Safety: BOOLEAN;
  181. 147 KeyNumber,
  182. 148 depth,
  183. 149 Init:CARDINAL;
  184. 150 alias:DBFile;
  185. 151 Header:HeaderNodeType;
  186. 152 KeyProc :KeyProcedure;
  187. ***** ^ undeclared identifier
  188. 153 posarray: Route;
  189. 154 CASE :BOOLEAN OF
  190. ***** ^ not supported yet
  191. ***** ^ 'POINTER' expected
  192. 155 TRUE: currentkey: KeyPointer;|
  193. 156 FALSE: numkey : RealKeyPointer;
  194. 157 END;
  195. 158 first, last: IndexBuffer;
  196. 159 currsize: CARDINAL;
  197. 160 buffsize: CARDINAL;
  198. 161 (* number of Nodes in Buffer *)
  199. 162 UpdateList:DBIndex;(* consider having list in seperate record
  200. 163 so that Index can be updated from more than one DBF *)
  201. 164 Hash:ARRAY[0..Bins-1] OF IndexBuffer;
  202. 165 END;
  203. 166
  204. 167 PROCEDURE HashP(number:LONGINT):CARDINAL;
  205. 168 TYPE
  206. 169 LSet=SET OF [0..31];
  207. 170 BEGIN
  208. 171 RETURN VAL(CARDINAL,LONGINT(LSet(127)*LSet(number) ) );
  209. 172 END HashP;
  210. 173
  211. 174 PROCEDURE AddToTable(ndx:DBIndex;BufPtr:IndexBuffer);
  212. 175 VAR
  213. 176 ptr:IndexBuffer;
  214. 177 h:CARDINAL;
  215. 178 BEGIN
  216. 179 h:=HashP(BufPtr^.number);
  217. 180 ptr:=ndx^.Hash[h];
  218. 181 BufPtr^.NHash:=ptr;
  219. 182 IF ptr#NIL THEN
  220. 183 ptr^.PHash:=BufPtr
  221. 184 END;
  222. 185 BufPtr^.PHash:=NIL;
  223. 186 ndx^.Hash[h]:=BufPtr;
  224. 187 END AddToTable;
  225. 188
  226. 189 PROCEDURE RemoveFromTable(ndx:DBIndex;BufPtr:IndexBuffer);
  227. 190 BEGIN
  228. 191 IF BufPtr^.PHash=NIL THEN
  229. 192 ndx^.Hash[HashP(BufPtr^.number)]:=BufPtr^.NHash;
  230. 193 ELSE
  231. 194 BufPtr^.PHash^.NHash:=BufPtr^.NHash
  232. 195 END;
  233. 196 IF BufPtr^.NHash#NIL THEN
  234. 197 BufPtr^.NHash^.PHash:=BufPtr^.PHash;
  235. 198 END;
  236. 199 BufPtr^.PHash:=NIL;
  237. 200 BufPtr^.NHash:=NIL;
  238. 201 END RemoveFromTable;
  239. 202
  240. 203 PROCEDURE InitPosarray( ndx: DBIndex);
  241. 204 VAR
  242. 205 i:CARDINAL;
  243. 206 BEGIN
  244. 207 FOR i:= 0 TO MaxDepth DO
  245. 208 ndx^.posarray[i].buffer:=NIL;
  246. 209 END;
  247. 210 END InitPosarray;
  248. 211
  249. 212 PROCEDURE InBuffer( ndx: DBIndex; nodenumber: LONGINT; VAR
  250. 213 BufPtr: IndexBuffer): BOOLEAN;
  251. 214
  252. 215 BEGIN
  253. 216 BufPtr:=ndx^.Hash[HashP(nodenumber)];
  254. 217 IF BufPtr = NIL THEN
  255. 218 RETURN FALSE
  256. 219 ELSE
  257. 220 LOOP
  258. 221 WITH BufPtr^ DO
  259. 222 IF (number = nodenumber) THEN
  260. 223 RETURN TRUE
  261. 224 END;
  262. 225 IF (NHash = NIL) THEN
  263. 226 RETURN FALSE
  264. 227 END;
  265. 228 END (* WITH *);
  266. 229 BufPtr := BufPtr^.NHash;
  267. 230 END; (* loop *)
  268. 231 END;
  269. 232 END InBuffer;
  270. 233
  271. 234 PROCEDURE AddBuffer( ndx:DBIndex;VAR buffer: IndexBuffer );
  272. 235 BEGIN
  273. 236 (* always add to top *)
  274. 237 buffer^.next:=ndx^.first;
  275. 238 buffer^.prev:=NIL;
  276. 239 IF buffer^.next=NIL
  277. 240 THEN
  278. 241 ndx^.last:=buffer;
  279. 242 ELSE
  280. 243 ndx^.first^.prev:=buffer;
  281. 244 END;
  282. 245 ndx^.first:=buffer;
  283. 246 buffer^.Lock:=TRUE;
  284. 247 INC(ndx^.currsize);
  285. 248 END AddBuffer;
  286. 249
  287. 250 PROCEDURE RemoveBuffer(ndx:DBIndex;VAR buffer: IndexBuffer );
  288. 251 BEGIN
  289. 252 IF buffer^.next=NIL
  290. 253 THEN
  291. 254 IF buffer^.prev=NIL
  292. 255 THEN
  293. 256 ndx^.first:=NIL;
  294. 257 ndx^.last:=NIL;
  295. 258 ELSE
  296. 259 ndx^.last:=buffer^.prev;
  297. 260 buffer^.prev^.next:=buffer^.next;
  298. 261 END;
  299. 262 ELSE
  300. 263 IF buffer^.prev=NIL
  301. 264 THEN
  302. 265 ndx^.first:=buffer^.next;
  303. 266 buffer^.next^.prev:=buffer^.prev;
  304. 267 ELSE
  305. 268 buffer^.next^.prev:=buffer^.prev;
  306. 269 buffer^.prev^.next:=buffer^.next;
  307. 270 END;
  308. 271 END;
  309. 272 DEC(ndx^.currsize);
  310. 273 END RemoveBuffer;
  311. 274
  312. 275
  313. 276 PROCEDURE WriteNode( ndx: DBIndex; nodenumber: LONGINT;
  314. 277 VAR nodeblock: NodeType);
  315. 278 VAR pos: LONGINT;
  316. 279 FileError: StringIO.ErrorMessage;
  317. 280
  318. 281 (*PROCEDURE Errorchk;(* diag *)
  319. 282 VAR
  320. 283 buffer:IndexBuffer;
  321. 284 i:CARDINAL;
  322. 285 BEGIN
  323. 286 IF NOT InBuffer(ndx,nodenumber,buffer)
  324. 287 THEN
  325. 288 HALT;
  326. 289 END;
  327. 290 FOR i:=0 TO 511 DO
  328. 291 IF buffer^.node[i]#nodeblock[i]
  329. 292 THEN
  330. 293 HALT;
  331. 294 END;
  332. 295 END;
  333. 296 END Errorchk;*)
  334. 297
  335. 298 BEGIN
  336. 299 (* IF nodenumber>VAL(LONGINT,1)
  337. 300 THEN
  338. 301 Errorchk
  339. 302 END; *)
  340. 303 pos := nodenumber * VAL(LONGINT, NodeSize);
  341. 304 HandleIO.SetFilePtr(ndx^.f, HandleIO.FromStart, pos);
  342. 305 FileError := HandleIO.BlockWrite(ndx^.f, ADR(nodeblock), NodeSize);
  343. 306 IF FileError # StringIO.NoError THEN
  344. 307 WARN('Block write failure in WriteNode');
  345. 308 END;
  346. 309 IF ndx^.Safety
  347. 310 THEN
  348. 311 HandleIO.UpdateDisk(ndx^.f);
  349. 312 END;
  350. 313
  351. 314 END WriteNode;
  352. 315
  353. 316 PROCEDURE InitNode(VAR node: NodeType);
  354. 317 BEGIN
  355. 318 Fill(ADR(node), NodeSize, 0C);
  356. 319 END InitNode;
  357. 320
  358. 321 PROCEDURE FindFreeBuffer( ndx:DBIndex;VAR buffer: IndexBuffer ):BOOLEAN;
  359. 322 BEGIN
  360. 323 buffer:=ndx^.last;
  361. 324 WHILE buffer^.Lock
  362. 325 DO
  363. 326 IF buffer^.prev=NIL
  364. 327 THEN
  365. 328 RETURN FALSE;
  366. 329 END;
  367. 330 buffer:=buffer^.prev;
  368. 331 END;
  369. 332 (* if one is looking for buffer it will be reused so write it
  370. 333 out if safety is off *)
  371. 334 IF buffer^.NeedToWrite
  372. 335 THEN
  373. 336 WriteNode(ndx,buffer^.number,buffer^.node);
  374. 337 END;
  375. 338 RETURN TRUE;
  376. 339 END FindFreeBuffer;
  377. 340
  378. 341 PROCEDURE GetBuffer( ndx:DBIndex;VAR buffer: IndexBuffer;
  379. 342 NodeNumber:LONGINT );
  380. 343 BEGIN
  381. 344 IF (( ndx^.buffsize>ndx^.currsize) AND DosAvail(8000))
  382. 345 THEN
  383. 346 DosAlloc(buffer,SIZE(buffer^));
  384. 347 ELSE;
  385. 348 IF FindFreeBuffer(ndx,buffer)
  386. 349 THEN
  387. 350 RemoveBuffer(ndx,buffer);
  388. 351 RemoveFromTable(ndx,buffer);
  389. 352 ELSE
  390. 353 DosAlloc(buffer,SIZE(buffer^));
  391. 354 END;
  392. 355 END;
  393. 356 AddBuffer(ndx,buffer);
  394. 357 (* init buffer *)
  395. 358 buffer^.number:=NodeNumber;
  396. 359 AddToTable(ndx,buffer);
  397. 360 (* buffer^.clean:=37513; diag *)
  398. 361 buffer^.NeedToWrite:=FALSE;
  399. 362 buffer^.Lock:=FALSE;
  400. 363 InitNode(buffer^.node);
  401. 364 END GetBuffer;
  402. 365
  403. 366 PROCEDURE ReadNode( ndx: DBIndex;
  404. 367 nodenumber: LONGINT;
  405. 368 VAR buffer: IndexBuffer);
  406. 369 (* the file associated with the index must already be open *)
  407. 370 VAR pos: LONGINT;
  408. 371 FileError: StringIO.ErrorMessage;
  409. 372 BEGIN
  410. 373 IF InBuffer(ndx,nodenumber,buffer)
  411. 374 THEN
  412. 375 RemoveBuffer(ndx,buffer);
  413. 376 AddBuffer(ndx,buffer);
  414. 377 RETURN
  415. 378 END;
  416. 379 GetBuffer(ndx,buffer,nodenumber);
  417. 380 (*buffer^.number:=nodenumber;*)
  418. 381 pos := nodenumber * VAL(LONGINT, NodeSize);
  419. 382 HandleIO.SetFilePtr(ndx^.f, HandleIO.FromStart, pos);
  420. 383 FileError := HandleIO.BlockRead(ndx^.f, ADR(buffer^.node), NodeSize);
  421. 384 IF FileError # StringIO.NoError THEN
  422. 385 WARN('Block read failure in ReadNode');
  423. 386 END;
  424. 387 END ReadNode;
  425. 388
  426. 389 PROCEDURE NewNode( ndx:DBIndex;VAR buffer:IndexBuffer) ;
  427. 390 BEGIN
  428. 391 IF ndx^.Header.FreeList=VAL(LONGINT,0)
  429. 392 THEN
  430. 393 GetBuffer(ndx,buffer,ndx^.Header.nextfreenode);
  431. 394 (*buffer^.number:=ndx^.Header.nextfreenode;*)
  432. 395 INC(ndx^.Header.nextfreenode)
  433. 396 ELSE
  434. 397 ReadNode(ndx,ndx^.Header.FreeList,buffer);
  435. 398 Move(ADR(buffer^.node),ADR(ndx^.Header.FreeList),4);
  436. 399 InitNode(buffer^.node);
  437. 400 END;
  438. 401
  439. 402 END NewNode;
  440. 403
  441. 404 PROCEDURE ReadIntoArray( ndx :DBIndex;
  442. 405 nodenumber: LONGINT;
  443. 406 level :CARDINAL);
  444. 407 BEGIN
  445. 408 IF ndx^.posarray[level].buffer#NIL
  446. 409 THEN
  447. 410 ndx^.posarray[level].buffer^.Lock:=FALSE;
  448. 411 END;
  449. 412 ReadNode(ndx, nodenumber, ndx^.posarray[level].buffer);
  450. 413 ndx^.posarray[level].buffer^.number:=nodenumber;
  451. 414 ndx^.posarray[level].buffer^.Lock:=TRUE;
  452. 415 END ReadIntoArray;
  453. 416
  454. 417 PROCEDURE ReadHeader( ndx:DBIndex);
  455. 418 BEGIN
  456. 419 HandleIO.SetFilePtr(ndx^.f, HandleIO.FromStart, 0);
  457. 420 StringIO.PrintMessage(HandleIO.BlockRead(ndx^.f,ADR(ndx^.Header),
  458. 421 SIZE(ndx^.Header)))
  459. 422 END ReadHeader;
  460. 423
  461. 424 PROCEDURE WriteHeader( ndx:DBIndex);
  462. 425 BEGIN
  463. 426 HandleIO.SetFilePtr(ndx^.f, HandleIO.FromStart, 0);
  464. 427 StringIO.PrintMessage(HandleIO.BlockWrite(ndx^.f,ADR(ndx^.Header),
  465. 428 SIZE(ndx^.Header)))
  466. 429
  467. 430 END WriteHeader;
  468. 431
  469. 432 PROCEDURE GetKeyPtr(VAR node: NodeType;
  470. 433 ndx: DBIndex;
  471. 434 keynumber: CARDINAL):KeyPointer;
  472. 435
  473. 436 BEGIN
  474. 437 RETURN ADR(node[4 +(keynumber * ndx^.Header.entrylength)]);
  475. 438 END GetKeyPtr;
  476. 439
  477. 440 PROCEDURE GetKey(VAR node: NodeType;
  478. 441 ndx: DBIndex;
  479. 442 keynumber: CARDINAL;
  480. 443 VAR key: EntryType);
  481. 444
  482. 445 BEGIN
  483. 446 (* entire procedure should be eliminated and placed in line.
  484. 447 changes are based on assumption that the max key size is 128
  485. 448 and 129 are avalable. error checking could be done in buildindex!!!!*)
  486. 449 Move(ADR(node[4 +(keynumber * ndx^.Header.entrylength)]), ADR(key),
  487. 450 ndx^.Header.entrylength);
  488. 451 key.value[ndx^.Header.keylength]:=0C;
  489. 452 END GetKey;
  490. 453
  491. 454 (*
  492. 455 PROCEDURE CompareKeyReal( ad1,ad2 : ADDRESS;size:CARDINAL) : CompareType;
  493. 456 TYPE
  494. 457 rp= RECORD
  495. 458 CASE:CARDINAL OF
  496. 459 1:
  497. 460 r:POINTER TO Real8;
  498. 461 | 2:
  499. 462 b:POINTER TO ARRAY[0..7] OF BYTE;
  500. 463 | 3:
  501. 464 a:ADDRESS;
  502. 465 END;
  503. 466 END;
  504. 467 VAR
  505. 468 r1,r2:rp;
  506. 469 BEGIN
  507. 470 r1.a:=ad1;
  508. 471 r2.a:=ad2;
  509. 472 IF (r1.r^ < r2.r^) THEN
  510. 473 RETURN LT
  511. 474 ELSIF (r1.b^ = r2.b^) THEN
  512. 475 RETURN EQ
  513. 476 ELSE
  514. 477 RETURN GT
  515. 478 END;
  516. 479 END CompareKeyReal;
  517. 480 *)
  518. 481 PROCEDURE CompareKeyReal(s1, s2 : ADDRESS;size:CARDINAL) : CompareType;
  519. 482 TYPE
  520. 483 rp= RECORD
  521. 484 CASE:CARDINAL OF
  522. 485 1:
  523. 486 r:POINTER TO Real8;
  524. 487 | 2:
  525. 488 c:POINTER TO CARDINAL;
  526. 489 | 3:
  527. 490 a:ADDRESS;
  528. 491 | 4:
  529. 492 off,seg:CARDINAL;
  530. 493 | 5:
  531. 494 b:POINTER TO BITSET;
  532. 495 END;
  533. 496 END;
  534. 497
  535. 498 VAR
  536. 499 TmpAdr1, TmpAdr2 : rp;
  537. 500 cnt : CARDINAL;
  538. 501 neg:BOOLEAN;
  539. 502 BEGIN
  540. 503 TmpAdr1.a := s1;
  541. 504 TmpAdr2.a := s2;
  542. 505 INC(TmpAdr1.off,6);
  543. 506 INC(TmpAdr2.off,6);
  544. 507 neg:=(15 IN TmpAdr1.b^) OR (15 IN TmpAdr2.b^);
  545. 508 cnt := 0;
  546. 509 WHILE cnt<4 DO
  547. 510 IF TmpAdr1.c^#TmpAdr2.c^ THEN
  548. 511 IF TmpAdr1.c^>TmpAdr2.c^ THEN
  549. 512 IF neg THEN
  550. 513 RETURN LT
  551. 514 ELSE
  552. 515 RETURN GT
  553. 516 END;
  554. 517 ELSE
  555. 518 IF neg THEN
  556. 519 RETURN GT
  557. 520 ELSE
  558. 521 RETURN LT;
  559. 522 END;
  560. 523 END;
  561. 524 ELSE
  562. 525 INC(cnt);
  563. 526 DEC(TmpAdr1.off,2);
  564. 527 DEC(TmpAdr2.off,2);
  565. 528 END;
  566. 529 END;
  567. 530 RETURN EQ;
  568. 531 END CompareKeyReal;
  569. 532
  570. 533 PROCEDURE CompareKey(s1, s2 : ADDRESS;size:CARDINAL) : CompareType;
  571. 534 VAR
  572. 535 TmpAdr1, TmpAdr2 : Address8086;
  573. 536 cnt : CARDINAL;
  574. 537 BEGIN
  575. 538 TmpAdr1.a := s1;
  576. 539 TmpAdr2.a := s2;
  577. 540 cnt := 0;
  578. 541 WHILE cnt<size DO
  579. 542 IF TmpAdr1.b^#TmpAdr2.b^ THEN
  580. 543 IF TmpAdr1.b^>TmpAdr2.b^ THEN
  581. 544 RETURN GT;
  582. 545 ELSE
  583. 546 RETURN LT;
  584. 547 END;
  585. 548 ELSE
  586. 549 IF (TmpAdr1.b^=0C)
  587. 550 THEN (* if on 0C were done *)
  588. 551 RETURN EQ
  589. 552 END;
  590. 553 INC(cnt);
  591. 554 INC(TmpAdr1.off);
  592. 555 INC(TmpAdr2.off);
  593. 556 END;
  594. 557 END;
  595. 558 RETURN EQ;
  596. 559 END CompareKey;
  597. 560
  598. 561 PROCEDURE FindPosition( ndx: DBIndex;
  599. 562 KeyValue: ADDRESS;
  600. 563 VAR found: BOOLEAN;
  601. 564 CompareP:CompareProc);
  602. 565
  603. 566 VAR level, keysinnode,
  604. 567 diff,
  605. 568 Top,Bottom,
  606. 569 crrntkeynum: CARDINAL;
  607. 570 done: BOOLEAN;
  608. 571 keyptr:KeyPointer;
  609. 572 nextnode: LONGINT;
  610. 573 BEGIN
  611. 574 IF OpenIndex(ndx)=FALSE
  612. 575 THEN
  613. 576 WARN('Error opening Index in FindPosition');
  614. 577 END;
  615. 578 nextnode := ndx^.Header.rootptr; (* start search with root node *)
  616. 579 level := 0;
  617. 580 found:=FALSE;
  618. 581 REPEAT
  619. 582 ReadIntoArray(ndx, nextnode, level);
  620. 583 WITH ndx^.posarray[level] DO
  621. 584 keysinnode := ORD(buffer^.node[0]);
  622. 585 Top:=keysinnode;
  623. 586 Bottom:=0;
  624. 587 crrntkeynum:=(Top)DIV 2;(* use shift operator? *)
  625. 588 done := FALSE;
  626. 589 (* IF buffer^.clean# 37513 THEN HALT END; diag *)
  627. 590 LOOP
  628. 591 keyptr:=GetKeyPtr(buffer^.node, ndx, crrntkeynum);
  629. 592 WITH keyptr^ DO
  630. 593 CASE CompareP(KeyValue,ADR(value),ndx^.Header.keylength) OF
  631. 594 LT: (* key is less than tested value *)
  632. 595 diff:=crrntkeynum-Bottom;
  633. 596 IF diff<1
  634. 597 THEN
  635. 598 EXIT; (* done *)
  636. 599 END;
  637. 600 Top:=crrntkeynum; (* check lower half *)
  638. 601 crrntkeynum:=Bottom+(diff DIV 2);
  639. 602 |GT: (* key is greater than test *)
  640. 603 diff:=Top-crrntkeynum;
  641. 604 IF diff<=1
  642. 605 THEN
  643. 606 crrntkeynum:=Top; (*done but currect one was top*)
  644. 607 keyptr:=GetKeyPtr(buffer^.node, ndx, crrntkeynum);
  645. 608 EXIT;
  646. 609 END;
  647. 610 Bottom:=crrntkeynum; (* Next check upper half *)
  648. 611 crrntkeynum:=Bottom+(diff DIV 2);
  649. 612 |EQ:
  650. 613
  651. 614 (* * * * * * * * * * * * * * * * * * * *testing stuff for ed *)
  652. 615 (* found a position - might not be the first one though *)
  653. 616 (* loop backwards through the index to find the first if many *)
  654. 617 LOOP
  655. 618 IF crrntkeynum < 1
  656. 619 THEN EXIT;
  657. 620 END; (* at the first *)
  658. 621 DEC(crrntkeynum);
  659. 622 keyptr := GetKeyPtr(buffer^.node,ndx,crrntkeynum);
  660. 623 IF CompareP(KeyValue,ADR(keyptr^.value),ndx^.Header.keylength) = GT
  661. 624 THEN INC(crrntkeynum);
  662. 625 keyptr := GetKeyPtr(buffer^.node,ndx,crrntkeynum);
  663. 626 EXIT;
  664. 627 END;
  665. 628 (* * * * * * * * * * * End of stuff by ed * * * * * * * * * * *)
  666. 629
  667. 630
  668. 631
  669. 632 END; (* end of loop and end of my stuff *)
  670. 633 found:= TRUE;
  671. 634 EXIT;
  672. 635 END; (* CASE *)
  673. 636 END;
  674. 637 END (*loop*);
  675. 638
  676. 639 (* compare the key to the keys in the rootnode until the fieldstring
  677. 640 <= currentkey or the last entry in the node is encountered *)
  678. 641 keynum := crrntkeynum;
  679. 642 (* currentkey set by getkey *)
  680. 643 nextnode:=keyptr^.lowernode;
  681. 644 END;
  682. 645 INC(level);
  683. 646 UNTIL nextnode=VAL(LONGINT,0);
  684. 647 ndx^.depth:=level-1;
  685. 648 ndx^.currentkey:=keyptr;
  686. 649 END FindPosition;
  687. 650
  688. 651 PROCEDURE FindPositionCh( ndx: DBIndex;
  689. 652 keystr: ARRAY OF CHAR;
  690. 653 VAR found: BOOLEAN);
  691. 654 VAR
  692. 655 TestStr:ARRAY[0..MaxKey] OF CHAR;
  693. 656 BEGIN
  694. 657 Fill(ADR(TestStr),MaxKey,' ');
  695. 658 Copy(keystr,0,Length(keystr),TestStr);
  696. 659 FindPosition(ndx,ADR(TestStr),found,CompareKey);
  697. 660 END FindPositionCh;
  698. 661
  699. 662 PROCEDURE FindPositionR( ndx: DBIndex;
  700. 663 KeyValue: Real8;
  701. 664 VAR found: BOOLEAN);
  702. 665 BEGIN
  703. 666 FindPosition(ndx,ADR(KeyValue),found,CompareKeyReal);
  704. 667 END FindPositionR;
  705. 668
  706. 669 PROCEDURE FindPositionN(ndx: DBIndex;
  707. 670 keystr: ARRAY OF CHAR;
  708. 671 VAR found: BOOLEAN);
  709. 672 VAR
  710. 673 KeyValue:Real8;
  711. 674 BEGIN
  712. 675 IF NOT StrToReal(keystr, 0,KeyValue) THEN KeyValue:=0.0 END;
  713. 676 FindPositionR(ndx,KeyValue,found);
  714. 677 END FindPositionN;
  715. 678
  716. 679 PROCEDURE AddRecord( alias: DBFile;
  717. 680 ndx: DBIndex);
  718. 681 VAR
  719. 682 fieldstring: ARRAY [1..MaxField] OF CHAR;
  720. 683 found: BOOLEAN;
  721. 684 key:
  722. 685 RECORD
  723. 686 CASE :BOOLEAN OF
  724. 687 TRUE:num:Real8;|
  725. 688 FALSE:str:ARRAY[0..7] OF CHAR;
  726. 689 END;
  727. 690 END;
  728. 691
  729. 692 BEGIN
  730. 693 IF OpenIndex(ndx)=FALSE
  731. 694 THEN
  732. 695 WARN('Error opening Index in AddRecord');
  733. 696 END;
  734. 697 EnterLock(ndx);
  735. 698 (* get key from record *);
  736. 699 ndx^.KeyProc(alias,ndx,fieldstring);
  737. 700 IF ndx^.Header.NumType THEN
  738. 701 IF NOT StrToReal(fieldstring, 0,key.num) THEN key.num:=0.0 END;
  739. 702 FindPositionR(ndx, key.num, found);
  740. 703 InsertEntry(ndx, key.str, Record(alias));
  741. 704 ELSE
  742. 705 FindPositionCh(ndx, fieldstring, found);
  743. 706 InsertEntry(ndx, fieldstring, Record(alias));
  744. 707 END; (* Now we have the position where the new Entry
  745. 708 should be inserted *)
  746. 709 ExitLock(ndx);
  747. 710 END AddRecord;
  748. 711
  749. 712 PROCEDURE DefaultKeyProcedure(alias: DBFile; ndx: DBIndex;
  750. 713 VAR str:ARRAY OF CHAR );
  751. 714 BEGIN
  752. 715 GetField(alias, ndx^.KeyNumber, str);
  753. 716
  754. 717 END DefaultKeyProcedure;
  755. 718
  756. 719 PROCEDURE AdjustUpperNode( ndx: DBIndex;VAR KeyStr:ARRAY OF CHAR;
  757. 720 level: CARDINAL);
  758. 721 (* need to pass keystring because may be fixing at the current level
  759. 722 but not in the route level-1 must point to worknode!!*)
  760. 723 VAR offset: CARDINAL;
  761. 724 upkey,key:KeyPointer;
  762. 725 BEGIN
  763. 726 (* do not check to see if it is nessary but make sure level#0 *)
  764. 727 IF (level=0) THEN RETURN END;
  765. 728 (*Adjust upernode*)
  766. 729 IF (ndx^.posarray[level-1].keynum#
  767. 730 ORD(ndx^.posarray[level-1].buffer^.node[0]))
  768. 731 THEN (* can simplify when changing upkey to upkey^ *)
  769. 732 upkey:=GetKeyPtr(ndx^.posarray[level-1].buffer^.node,ndx,
  770. 733 ndx^.posarray[level-1].keynum);
  771. 734 Move(ADR(KeyStr), ADR(upkey^.value), ndx^.Header.keylength);
  772. 735 IF ndx^.Safety OR NOT ndx^.Exclusive
  773. 736 THEN
  774. 737 WriteNode(ndx, ndx^.posarray[level-1].buffer^.number,
  775. 738 ndx^.posarray[level-1].buffer^.node);
  776. 739 ELSE
  777. 740 ndx^.posarray[level-1].buffer^.NeedToWrite:=TRUE;
  778. 741 END;
  779. 742 ELSE
  780. 743 AdjustUpperNode(ndx,KeyStr,level-1);
  781. 744 END;
  782. 745 END AdjustUpperNode;
  783. 746
  784. 747 PROCEDURE DeleteEntry(ndx: DBIndex;
  785. 748 deletelevel: CARDINAL);
  786. 749 VAR offset: CARDINAL;
  787. 750 upkey,key:KeyPointer;
  788. 751 empty:BOOLEAN;
  789. 752 BEGIN
  790. 753 (* 4/21/89 notes for changes pos is not need as parameter
  791. 754 if top node is changed need to fix all the way down if
  792. 755 needed not just one as it is there is some chance of error.
  793. 756 cosider making procedure to fix uper node as it is used in
  794. 757 move keys also *)
  795. 758 (* Find the offset of the keyentry following
  796. 759 the entry to be deleted, and then shift the rest of the
  797. 760 node up to cover the deleted node *)
  798. 761 ndx^.Changed:=TRUE;
  799. 762 offset := ((ndx^.posarray[deletelevel].keynum + 1) * (ndx^.Header.entrylength)) + 4;
  800. 763 Move(ADR(ndx^.posarray[deletelevel].buffer^.node[offset]),
  801. 764 ADR(ndx^.posarray[deletelevel].buffer^.node[offset-ndx^.Header.entrylength]),
  802. 765 NodeSize-offset);
  803. 766 (* not correct or nessisary ?
  804. 767 Fill(ADR(ndx^.posarray[deletelevel].buffer^.
  805. 768 node[offset -ndx^.Header.entrylength]), ndx^.Header.entrylength, 0C);*)
  806. 769
  807. 770 (* Next decrement the number of keys in the node and
  808. 771 write the decremented number in the first byte of the
  809. 772 node. *)
  810. 773 empty:=FALSE;
  811. 774 empty:=(ndx^.posarray[deletelevel].buffer^.node[0])=0C;
  812. 775 IF NOT empty THEN
  813. 776 DEC(ndx^.posarray[deletelevel].buffer^.node[0]);
  814. 777 empty:=(ndx^.posarray[deletelevel].buffer^.node[0]=0C) AND
  815. 778 (deletelevel =ndx^.depth)
  816. 779 END;
  817. 780 IF (deletelevel > 0)
  818. 781 THEN
  819. 782 IF empty
  820. 783 THEN (* THE NODE IS EMPTY *)
  821. 784 (* posarray must be good *)
  822. 785 (* put in freenode list *)
  823. 786 Move(ADR(ndx^.Header.FreeList),
  824. 787 ADR(ndx^.posarray[deletelevel].buffer^.node),4);
  825. 788 ndx^.Header.FreeList:=ndx^.posarray[deletelevel].buffer^.number;
  826. 789 DeleteEntry(ndx,deletelevel-1);
  827. 790 ELSE;
  828. 791 (* Check to see if deleted top node *)
  829. 792 IF deletelevel=ndx^.depth
  830. 793 THEN
  831. 794 offset:=1
  832. 795 ELSE
  833. 796 offset:=0
  834. 797 END;
  835. 798 IF ndx^.posarray[deletelevel].keynum =
  836. 799 ( ORD(ndx^.posarray[deletelevel].buffer^.node[0])+1-offset)
  837. 800 THEN
  838. 801 key:=GetKeyPtr(ndx^.posarray[deletelevel].buffer^.node,
  839. 802 ndx,ndx^.posarray[deletelevel].keynum-1);
  840. 803 AdjustUpperNode(ndx,
  841. 804 key^.value,
  842. 805 deletelevel);
  843. 806 END;
  844. 807 END;
  845. 808 END; (* if *)
  846. 809
  847. 810 IF ndx^.Safety OR NOT ndx^.Exclusive
  848. 811 THEN
  849. 812 WriteNode(ndx, ndx^.posarray[deletelevel].buffer^.number,
  850. 813 ndx^.posarray[deletelevel].buffer^.node);
  851. 814 ELSE
  852. 815 ndx^.posarray[deletelevel].buffer^.NeedToWrite:=TRUE;
  853. 816 END;
  854. 817 END DeleteEntry;
  855. 818
  856. 819
  857. 820 PROCEDURE DeleteCurrentEntry( ndx: DBIndex);
  858. 821 VAR
  859. 822 rec:LONGINT;
  860. 823 BEGIN
  861. 824 IF OpenIndex(ndx)=FALSE
  862. 825 THEN
  863. 826 WARN('Error opening Index in DeleteCurrentEntry');
  864. 827 END;
  865. 828 rec:=ndx^.currentkey^.recordnum;
  866. 829 EnterLock(ndx);
  867. 830 IF rec=ndx^.currentkey^.recordnum THEN (* do not delete if not there *)
  868. 831 DeleteEntry(ndx, ndx^.depth);
  869. 832 END;
  870. 833 ExitLock(ndx);
  871. 834 END DeleteCurrentEntry;
  872. 835
  873. 836 PROCEDURE UpdateIndexHeader(ndx :DBIndex );
  874. 837
  875. 838 VAR
  876. 839 Buffer:IndexBuffer;
  877. 840 BEGIN
  878. 841 IF NOT ndx^.open
  879. 842 THEN
  880. 843 RETURN;
  881. 844 END;
  882. 845 HandleIO.SetFilePtr(ndx^.f,HandleIO.FromStart,VAL(LONGINT,0));
  883. 846 StringIO.PrintMessage(
  884. 847 HandleIO.BlockWrite(ndx^.f,ADR(ndx^.Header),SIZE(ndx^.Header)));
  885. 848 IF NOT ndx^.Safety AND ndx^.Exclusive
  886. 849 THEN (* Write out Buffers if safety off*)
  887. 850 Buffer:=ndx^.first;
  888. 851 WHILE Buffer#NIL
  889. 852 DO
  890. 853 IF Buffer^.NeedToWrite
  891. 854 THEN
  892. 855 WriteNode(ndx,Buffer^.number,Buffer^.node);
  893. 856 Buffer^.NeedToWrite:=FALSE;
  894. 857 END;
  895. 858 Buffer:=Buffer^.next;
  896. 859 END;
  897. 860 END;
  898. 861 END UpdateIndexHeader;
  899. 862
  900. 863
  901. 864
  902. 865 PROCEDURE InsertEntry( ndx: DBIndex;
  903. 866 kstr: ARRAY OF CHAR;
  904. 867 recno: LONGINT);
  905. 868 VAR i, level, middle: CARDINAL;
  906. 869 tempkey:EntryType;
  907. 870 NewRoot,NewBuffer:IndexBuffer;
  908. 871 noOverflow,InHighNode: BOOLEAN;
  909. 872 (*diag,*)oldnodenum, newnodenum, lowernodenum: LONGINT;
  910. 873 key:
  911. 874 RECORD
  912. 875 CASE :BOOLEAN OF
  913. 876 TRUE:num:Real8;|
  914. 877 FALSE:str:ARRAY[0..7] OF CHAR;
  915. 878 END;
  916. 879 END;
  917. 880
  918. 881
  919. 882
  920. 883 PROCEDURE AddKeyTo( lower, recnum: LONGINT; VAR node: NodeType;
  921. 884 val: ARRAY OF CHAR; NewKey:BOOLEAN);
  922. 885 (* This procedure assumes that there is room in the node for another
  923. 886 key entry; it does not test for correct positioning, it assumes
  924. 887 that the ndx^.posarray has been correctly updated by all prior
  925. 888 operations *)
  926. 889 VAR moveblocksize, i, entrypos, keystomove : CARDINAL;
  927. 890
  928. 891 BEGIN
  929. 892 (* consider changing to copy into entry then move all *)
  930. 893 entrypos := ndx^.posarray[level].keynum;
  931. 894 keystomove := ORD(node[0])-entrypos+1;
  932. 895 node[0] := CHR(ORD(node[0])+1);
  933. 896 i := 4 + (entrypos * ndx^.Header.entrylength); (* 4 bytes reserved for key count *)
  934. 897 (* make space for the new entry *)
  935. 898 moveblocksize := keystomove*ndx^.Header.entrylength+4;
  936. 899 ShiftArrayRight((* from *) ADR(node[i]),
  937. 900 (* size *) moveblocksize ,
  938. 901 (* distance *) ndx^.Header.entrylength);
  939. 902 Move(ADR(recnum), ADR(node[i+4]), 4);
  940. 903 (* trims to size *)
  941. 904 Move(ADR(val),ADR(node[i+8]), ndx^.Header.entrylength - 8);
  942. 905 Move(ADR(lower), ADR(node[i]), 4);
  943. 906 (* the Move statement modifies the pointer after the inserted key
  944. 907 so that it points to the appropriate node. It is hard to
  945. 908 remember that the only reason an entry would be inserted into
  946. 909 a node other than a leaf node is because the lower node was split. *)
  947. 910 IF (ndx^.depth=level)
  948. 911 THEN
  949. 912 IF NewKey THEN
  950. 913 ndx^.currentkey:=ADR(node[i])
  951. 914 END;
  952. 915 IF (keystomove=1)
  953. 916 THEN
  954. 917 AdjustUpperNode(ndx,val,level)
  955. 918 END;
  956. 919 END;
  957. 920 END AddKeyTo;
  958. 921
  959. 922 PROCEDURE Split(VAR old, new: IndexBuffer);
  960. 923 VAR
  961. 924 c:CHAR;
  962. 925 key:EntryType;
  963. 926 i, j, middlekeypos,
  964. 927 keysinold: CARDINAL;
  965. 928 BEGIN
  966. 929 keysinold := ORD(old^.node[0]);
  967. 930 new^.node := old^.node;
  968. 931 (* if a key has been handed up from a split node it points to the
  969. 932 newnode created by the last split *)
  970. 933 (* save node numbers in case root node is being split *)
  971. 934 newnodenum:=new^.number;
  972. 935 oldnodenum:=old^.number;
  973. 936 middle := (ndx^.Header.keyspernode DIV 2);
  974. 937 keysinold := keysinold - middle;
  975. 938 middlekeypos := 4 + (middle)* ndx^.Header.entrylength;
  976. 939 (* middlekeypos is the END of the middlekey *)
  977. 940 Fill(ADR(new^.node[middlekeypos]), NodeSize - middlekeypos, 0C);
  978. 941 (* the new node gets the first keys, the rest are nulled out *)
  979. 942 Move(ADR((*from*) old^.node[middlekeypos]),
  980. 943 (* to *) ADR(old^.node[4]),
  981. 944 (*size*) (NodeSize-middlekeypos));
  982. 945 Fill(ADR(old^.node[8+keysinold*ndx^.Header.entrylength]),
  983. 946 NodeSize-(8+keysinold*ndx^.Header.entrylength),0C);
  984. 947 new^.node[0] := CHR(middle);
  985. 948 old^.node[0] := CHR(keysinold);
  986. 949 (* IF new=old
  987. 950 THEN
  988. 951 HALT;
  989. 952 END; (* diag *)
  990. 953 *)
  991. 954 IF ndx^.posarray[level].keynum <= middle THEN
  992. 955 (* insert into new node ( lowernode ) *)
  993. 956 (* new is yet in posarray so must trick Addkeyto to not
  994. 957 try and adjust upper node as it will be inserted latter*)
  995. 958 INC(new^.node[0]);
  996. 959 AddKeyTo(lowernodenum, recno, new^.node, kstr,TRUE);
  997. 960 DEC(new^.node[0]);
  998. 961 INC(middle); (* because an entry has been inserted ahead of it *)
  999. 962 GetKey(new^.node,ndx,middle-1,key); (* get key value to
  1000. 963 insert in lowernode before we lose it *)
  1001. 964 IF lowernodenum#VAL(LONGINT,0)
  1002. 965 THEN (* not at leaf DBASEIII does not store entire lastkey in non leaf
  1003. 966 nodes *)
  1004. 967 DEC(new^.node[0])
  1005. 968 END;
  1006. 969 (* force new pos array *)
  1007. 970 InHighNode:=FALSE;
  1008. 971 (* need to put writes here because the readintoarray
  1009. 972 will lose a node *)
  1010. 973 IF ndx^.Safety OR NOT ndx^.Exclusive
  1011. 974 THEN
  1012. 975 WriteNode(ndx, new^.number, new^.node);
  1013. 976 WriteNode(ndx, old^.number, old^.node);
  1014. 977 ELSE
  1015. 978 new^.NeedToWrite:=TRUE;
  1016. 979 old^.NeedToWrite:=TRUE;
  1017. 980 END;
  1018. 981 ReadIntoArray(ndx, new^.number, level);
  1019. 982 old^.Lock:=FALSE;(* unlock other buffer *)
  1020. 983 ELSE
  1021. 984 (* insert into old (high) node *)
  1022. 985 GetKey(new^.node,ndx,middle-1,key); (* get key value to
  1023. 986 insert in lowernode before we lose it *)
  1024. 987 IF lowernodenum#VAL(LONGINT,0)
  1025. 988 THEN (* not at leaf DBASEIII does not store entire lastkey in non leaf
  1026. 989 nodes *)
  1027. 990 DEC(new^.node[0])
  1028. 991 END;
  1029. 992 ndx^.posarray[level].keynum := (ndx^.posarray[level].keynum - middle) ;
  1030. 993 AddKeyTo(lowernodenum, recno, old^.node, kstr,TRUE);
  1031. 994 IF ndx^.Safety OR NOT ndx^.Exclusive
  1032. 995 THEN
  1033. 996 WriteNode(ndx, new^.number, new^.node);
  1034. 997 WriteNode(ndx, old^.number, old^.node);
  1035. 998 ELSE
  1036. 999 new^.NeedToWrite:=TRUE;
  1037. 1000 old^.NeedToWrite:=TRUE;
  1038. 1001 END;
  1039. 1002 InHighNode:=TRUE;
  1040. 1003 (* force new pos array *)
  1041. 1004 (* ReadIntoArray(ndx, old^.number, level); not neeed *)
  1042. 1005 new^.Lock:=FALSE;(* unlock other buffer *)
  1043. 1006 END;
  1044. 1007
  1045. 1008 (* in order to place new node in tree, act as if was inserting
  1046. 1009 the last key in the lower(new) node, so must save info *)
  1047. 1010 lowernodenum:=newnodenum;
  1048. 1011 Assign(key.value,kstr);
  1049. 1012 recno:=key.recordnum;
  1050. 1013 END Split;
  1051. 1014
  1052. 1015 PROCEDURE Balance(level:CARDINAL);
  1053. 1016 VAR
  1054. 1017 offset,
  1055. 1018 count,
  1056. 1019 insertpos,
  1057. 1020 keystomove,
  1058. 1021 keys,
  1059. 1022 downkeys,
  1060. 1023 upkeys:CARDINAL;
  1061. 1024 UpBuffer,DownBuffer:IndexBuffer;
  1062. 1025 upkey,tempkey:EntryType;
  1063. 1026 (* found:BOOLEAN;(*diag *) *)
  1064. 1027
  1065. 1028 PROCEDURE Movekeys ;
  1066. 1029 BEGIN
  1067. 1030
  1068. 1031 noOverflow:=TRUE;
  1069. 1032 IF upkeys > downkeys
  1070. 1033 THEN (* move to lower node *)
  1071. 1034 keystomove:=(keys-downkeys+1) DIV 2;
  1072. 1035 count:=keystomove;
  1073. 1036 WHILE count>0 DO
  1074. 1037 (* get key to move and save*)
  1075. 1038 (* remove from bottom place on top *)
  1076. 1039 GetKey(ndx^.posarray[level].buffer^.node,
  1077. 1040 ndx, 0, tempkey);
  1078. 1041 ndx^.posarray[level].keynum:=0;
  1079. 1042 DeleteEntry(ndx, level);
  1080. 1043 ndx^.posarray[level].keynum:=ORD(DownBuffer^.node[0]);
  1081. 1044 DEC(ndx^.posarray[level-1].keynum);
  1082. 1045 AddKeyTo(tempkey.lowernode,tempkey.recordnum,
  1083. 1046 DownBuffer^.node,tempkey.value,FALSE);(* addkey does not write *)
  1084. 1047 INC(ndx^.posarray[level-1].keynum);
  1085. 1048 DEC(count);
  1086. 1049 END (* while *);
  1087. 1050 IF insertpos >= keystomove THEN
  1088. 1051 (* insert into new node ( lowernode ) *)
  1089. 1052 ndx^.posarray[level].keynum:=insertpos-keystomove;
  1090. 1053 AddKeyTo(lowernodenum, recno, ndx^.posarray[level].buffer^.node, kstr,TRUE);
  1091. 1054 (* force new pos array *)
  1092. 1055 (* need to put writes here because the readintoarray
  1093. 1056 will lose a node *)
  1094. 1057 IF ndx^.Safety OR NOT ndx^.Exclusive
  1095. 1058 THEN
  1096. 1059 WriteNode(ndx, ndx^.posarray[level].buffer^.number,
  1097. 1060 ndx^.posarray[level].buffer^.node);
  1098. 1061 WriteNode(ndx, DownBuffer^.number, DownBuffer^.node);
  1099. 1062 ELSE
  1100. 1063 ndx^.posarray[level].buffer^.NeedToWrite:=TRUE;
  1101. 1064 DownBuffer^.NeedToWrite:=TRUE;
  1102. 1065 END;
  1103. 1066 ELSE
  1104. 1067 (* insert into other node *)
  1105. 1068 ndx^.posarray[level].keynum :=downkeys+insertpos;
  1106. 1069 DEC(ndx^.posarray[level-1].keynum);
  1107. 1070 AddKeyTo(lowernodenum, recno, DownBuffer^.node, kstr,TRUE);
  1108. 1071 IF ndx^.Safety OR NOT ndx^.Exclusive
  1109. 1072 THEN
  1110. 1073 WriteNode(ndx, ndx^.posarray[level].buffer^.number,
  1111. 1074 ndx^.posarray[level].buffer^.node);
  1112. 1075 WriteNode(ndx, DownBuffer^.number, DownBuffer^.node);
  1113. 1076 ELSE
  1114. 1077 ndx^.posarray[level].buffer^.NeedToWrite:=TRUE;
  1115. 1078 DownBuffer^.NeedToWrite:=TRUE;
  1116. 1079 END;
  1117. 1080 (* force new pos array *)
  1118. 1081 ReadIntoArray(ndx, DownBuffer^.number, level);
  1119. 1082 END;
  1120. 1083
  1121. 1084 ELSE (* move to upper *)
  1122. 1085 keystomove:=(keys-upkeys+1) DIV 2;
  1123. 1086 count:=keystomove;
  1124. 1087 WHILE count>0 DO
  1125. 1088 (* get key to move and save*)
  1126. 1089 (* remove from top place on bottom *)
  1127. 1090 GetKey(ndx^.posarray[level].buffer^.node,
  1128. 1091 ndx,ORD(ndx^.posarray[level].buffer^.node[0])-1, tempkey);
  1129. 1092 ndx^.posarray[level].keynum:=
  1130. 1093 ORD(ndx^.posarray[level].buffer^.node[0])-1;
  1131. 1094 DeleteEntry(ndx, level);
  1132. 1095 ndx^.posarray[level].keynum:=0;
  1133. 1096 AddKeyTo(tempkey.lowernode,tempkey.recordnum,
  1134. 1097 UpBuffer^.node,tempkey.value,FALSE);(* addkey does not write *)
  1135. 1098 DEC(count);
  1136. 1099 END (* while *);
  1137. 1100
  1138. 1101 (* delete key fixed upper node *)
  1139. 1102 IF insertpos < ORD(ndx^.posarray[level].buffer^.node[0]) THEN
  1140. 1103 (* insert into old node *)
  1141. 1104 ndx^.posarray[level].keynum:=insertpos;
  1142. 1105 AddKeyTo(lowernodenum, recno, ndx^.posarray[level].buffer^.node, kstr,TRUE);
  1143. 1106 (* force new pos array *)
  1144. 1107 (* need to put writes here because the readintoarray
  1145. 1108 will lose a node *)
  1146. 1109 IF ndx^.Safety OR NOT ndx^.Exclusive
  1147. 1110 THEN
  1148. 1111 WriteNode(ndx, ndx^.posarray[level].buffer^.number,
  1149. 1112 ndx^.posarray[level].buffer^.node);
  1150. 1113 WriteNode(ndx, UpBuffer^.number, UpBuffer^.node);
  1151. 1114 ELSE
  1152. 1115 ndx^.posarray[level].buffer^.NeedToWrite:=TRUE;
  1153. 1116 UpBuffer^.NeedToWrite:=TRUE;
  1154. 1117 END;
  1155. 1118 ELSE
  1156. 1119 (* insert into other node *)
  1157. 1120 ndx^.posarray[level].keynum :=
  1158. 1121 insertpos-ORD(ndx^.posarray[level].buffer^.node[0]);
  1159. 1122 INC(ndx^.posarray[level-1].keynum);
  1160. 1123 AddKeyTo(lowernodenum, recno, UpBuffer^.node, kstr,TRUE);
  1161. 1124 IF ndx^.Safety OR NOT ndx^.Exclusive
  1162. 1125 THEN
  1163. 1126 WriteNode(ndx, ndx^.posarray[level].buffer^.number,
  1164. 1127 ndx^.posarray[level].buffer^.node);
  1165. 1128 WriteNode(ndx, UpBuffer^.number, UpBuffer^.node);
  1166. 1129 ELSE
  1167. 1130 ndx^.posarray[level].buffer^.NeedToWrite:=TRUE;
  1168. 1131 UpBuffer^.NeedToWrite:=TRUE;
  1169. 1132 END;
  1170. 1133 (* force new pos array *)
  1171. 1134 ReadIntoArray(ndx, UpBuffer^.number, level);
  1172. 1135 END;
  1173. 1136
  1174. 1137 END;
  1175. 1138
  1176. 1139 END Movekeys ;
  1177. 1140
  1178. 1141 PROCEDURE CanBalance():BOOLEAN ;
  1179. 1142 BEGIN
  1180. 1143 IF (upkeys>=keys) AND (downkeys>=keys)
  1181. 1144 THEN
  1182. 1145 RETURN FALSE;
  1183. 1146 ELSIF (upkeys>downkeys) AND (keys-downkeys=1)
  1184. 1147 THEN (* downkey has only one place *)
  1185. 1148 IF ndx^.posarray[level].keynum=0 THEN
  1186. 1149 RETURN FALSE;
  1187. 1150 END;
  1188. 1151 ELSIF (upkeys<=downkeys) AND (keys-upkeys=1)
  1189. 1152 THEN (* upkey has only one place *)
  1190. 1153 IF (ndx^.posarray[level].keynum+1)>=keys THEN
  1191. 1154 RETURN FALSE;
  1192. 1155 END;
  1193. 1156 END;
  1194. 1157 RETURN TRUE;
  1195. 1158
  1196. 1159 END CanBalance;
  1197. 1160
  1198. 1161 BEGIN (*balance *)
  1199. 1162 downkeys:=65000;
  1200. 1163 upkeys:=65000;
  1201. 1164 DownBuffer:=NIL;
  1202. 1165 UpBuffer:=NIL;
  1203. 1166 IF (level=0) OR (level#ndx^.depth)
  1204. 1167 THEN
  1205. 1168 (* Because of complications do not balace nonleaf nodes *)
  1206. 1169 NewNode(ndx,NewBuffer);
  1207. 1170 Split(ndx^.posarray[level].buffer, NewBuffer);
  1208. 1171 RETURN;
  1209. 1172 END;
  1210. 1173 insertpos:=ndx^.posarray[level].keynum;
  1211. 1174 keys:=ORD(ndx^.posarray[level].buffer^.node[0]);
  1212. 1175 IF ndx^.posarray[level-1].keynum <
  1213. 1176 (ORD(ndx^.posarray[level-1].buffer^.node[0])-1)
  1214. 1177 THEN (* get uper node (same level *)
  1215. 1178 GetKey(ndx^.posarray[level-1].buffer^.node,
  1216. 1179 ndx, ndx^.posarray[level-1].keynum+1, tempkey);
  1217. 1180 ReadNode(ndx,tempkey.lowernode,UpBuffer);
  1218. 1181 UpBuffer^.Lock:=TRUE;
  1219. 1182 upkeys:=ORD(UpBuffer^.node[0]);
  1220. 1183 END;
  1221. 1184 IF ndx^.posarray[level-1].keynum > 0
  1222. 1185 THEN (* get lowernode (same level) *)
  1223. 1186 GetKey(ndx^.posarray[level-1].buffer^.node,
  1224. 1187 ndx, ndx^.posarray[level-1].keynum-1, tempkey);
  1225. 1188 ReadNode(ndx,tempkey.lowernode,DownBuffer);
  1226. 1189 DownBuffer^.Lock:=TRUE;
  1227. 1190 downkeys:=ORD(DownBuffer^.node[0]);
  1228. 1191 END;
  1229. 1192 (* determine if one can just move keys *)
  1230. 1193 IF CanBalance()
  1231. 1194 THEN
  1232. 1195 Movekeys;
  1233. 1196 (* ChkInd.NDXChk(ndx);
  1234. 1197 FindPositionCh(ndx,kstr,found);
  1235. 1198 IF NOT found THEN HALT END;*)
  1236. 1199 ELSE
  1237. 1200 NewNode(ndx,NewBuffer);
  1238. 1201 Split(ndx^.posarray[level].buffer, NewBuffer);
  1239. 1202 END;
  1240. 1203 IF DownBuffer#NIL THEN DownBuffer^.Lock:=FALSE END;
  1241. 1204 IF UpBuffer#NIL THEN UpBuffer^.Lock:=FALSE END;
  1242. 1205 END Balance;
  1243. 1206
  1244. 1207 BEGIN (* Insert Entry *)
  1245. 1208 (* update current key to keep all up to date *)
  1246. 1209 EnterLock(ndx);
  1247. 1210 (* diag:=recno (* diag *);*)
  1248. 1211 ndx^.Changed:=TRUE;
  1249. 1212 InHighNode:=FALSE;
  1250. 1213 (*IF ndx^.Header.NumType
  1251. 1214 THEN
  1252. 1215 Move(ADR(kstr),ADR(NewKey.value),8);
  1253. 1216 ELSE
  1254. 1217 Assign(kstr,NewKey.value);
  1255. 1218 END;
  1256. 1219 NewKey.lowernode:=VAL(LONGINT,0);
  1257. 1220 NewKey.recordnum:=recno; *)
  1258. 1221 level := ndx^.depth;
  1259. 1222 lowernodenum := VAL(LONGINT,0);
  1260. 1223 REPEAT
  1261. 1224 noOverflow := ORD(ndx^.posarray[level].buffer^.node[0]) < ndx^.Header.keyspernode;
  1262. 1225 IF noOverflow THEN
  1263. 1226 AddKeyTo(lowernodenum, recno, ndx^.posarray[level].buffer^.node, kstr,TRUE);
  1264. 1227 IF InHighNode
  1265. 1228 THEN
  1266. 1229 INC(ndx^.posarray[level].keynum);
  1267. 1230 END;
  1268. 1231 IF ndx^.Safety OR NOT ndx^.Exclusive
  1269. 1232 THEN
  1270. 1233 WriteNode(ndx, ndx^.posarray[level].buffer^.number,
  1271. 1234 ndx^.posarray[level].buffer^.node);
  1272. 1235 ELSE
  1273. 1236 ndx^.posarray[level].buffer^.NeedToWrite:=TRUE;
  1274. 1237 END;
  1275. 1238 ELSE
  1276. 1239 Balance(level);
  1277. 1240 (* find out where kstr belongs and insert it *)
  1278. 1241 IF level = 0 THEN (* the root node was split *)
  1279. 1242 INC(ndx^.buffsize,2);(* enlarge buffer *)
  1280. 1243 INC(ndx^.depth); (* prepare to add another level to the map *)
  1281. 1244 FOR i := ndx^.depth TO 1 BY -1 DO
  1282. 1245 ndx^.posarray[i] := ndx^.posarray[i-1]
  1283. 1246 END; (* slide all the keypositions in the map up one notch *)
  1284. 1247 NewNode(ndx,NewRoot);
  1285. 1248 (* force NewRoot into root position *)
  1286. 1249 ndx^.Header.rootptr := NewRoot^.number;
  1287. 1250 ReadIntoArray(ndx, NewRoot^.number, 0);
  1288. 1251 (* KEYNUMBERS BEGIN at ZERO *)
  1289. 1252 ndx^.posarray[0].keynum := 0;
  1290. 1253 NewBuffer^.Lock:=FALSE;
  1291. 1254 AddKeyTo(oldnodenum, VAL(LONGINT,0), NewRoot^.node, '',FALSE);
  1292. 1255 (* the new node initially contains no key but points to the
  1293. 1256 new node which was written when the old root was split *)
  1294. 1257 (* the number of entries in the node is now 1 *)
  1295. 1258 (* now a key is inserted ahead of the 'keyless' pointer *)
  1296. 1259 AddKeyTo(newnodenum, recno, NewRoot^.node, kstr,TRUE);
  1297. 1260 ndx^.posarray[0].buffer^.node[0]:= 1C;(* top key does not count *)
  1298. 1261 IF ndx^.posarray[1].buffer^.number = newnodenum THEN
  1299. 1262 ndx^.posarray[0].keynum := 0
  1300. 1263 ELSE
  1301. 1264 ndx^.posarray[0].keynum := 1
  1302. 1265 END;
  1303. 1266 IF ndx^.Safety OR NOT ndx^.Exclusive
  1304. 1267 THEN
  1305. 1268 WriteNode(ndx, ndx^.Header.rootptr, NewRoot^.node);
  1306. 1269 ELSE
  1307. 1270 NewRoot^.NeedToWrite:=TRUE;
  1308. 1271 END;
  1309. 1272 noOverflow := TRUE;
  1310. 1273 END (* if *);
  1311. 1274 (* if safety is on update header when a node splits *)
  1312. 1275 IF ndx^.Safety OR NOT ndx^.Exclusive
  1313. 1276 THEN
  1314. 1277 UpdateIndexHeader(ndx);
  1315. 1278 END;
  1316. 1279
  1317. 1280 END (* if *);
  1318. 1281 IF level > 0 THEN
  1319. 1282 DEC(level);
  1320. 1283 END (* if *);
  1321. 1284 UNTIL noOverflow;
  1322. 1285 ExitLock(ndx);
  1323. 1286 (* ChkInd.NDXChk(ndx);*)
  1324. 1287 (* !!!! diag *)
  1325. 1288 (* IF diag # ndx^.currentkey^.recordnum
  1326. 1289 THEN HALT END (*diag *); *)
  1327. 1290 END InsertEntry;
  1328. 1291
  1329. 1292 PROCEDURE BuildIndex(ndx: DBIndex;
  1330. 1293 keyexp: ARRAY OF CHAR):CARDINAL;
  1331. 1294 VAR
  1332. 1295 Fptr:DBFieldPtr;
  1333. 1296 BEGIN
  1334. 1297 IF NOT OpenDBF(ndx^.alias)
  1335. 1298 THEN (* check to make sure the file is open *)
  1336. 1299 WARN('Not able to DBFile file in BuildIndex');
  1337. 1300 END;
  1338. 1301 CrunchBlanks(keyexp);
  1339. 1302 CAPstr(keyexp);
  1340. 1303 ndx^.KeyNumber:=PosOfField(ndx^.alias,keyexp);
  1341. 1304 IF ndx^.KeyNumber=0 THEN
  1342. 1305 WARN('Bad index expression in BuildIndex');
  1343. 1306 END;
  1344. 1307 Fptr:=FieldList(ndx^.alias);
  1345. 1308 RETURN BuildCompIndex(ndx,Fptr^[ndx^.KeyNumber].fldtype,
  1346. 1309 keyexp,Fptr^[ndx^.KeyNumber].size);
  1347. 1310 END BuildIndex;
  1348. 1311
  1349. 1312 PROCEDURE BuildCompIndex( ndx: DBIndex;
  1350. 1313 type:CHAR; (* C or N *)
  1351. 1314 keyexp:ARRAY OF CHAR;
  1352. 1315 size: CARDINAL
  1353. 1316 ):CARDINAL;
  1354. 1317 VAR oldbuffsize,
  1355. 1318 olddbbuffersize,
  1356. 1319 i,
  1357. 1320 ActionTaken: CARDINAL;
  1358. 1321 worknode: NodeType;
  1359. 1322 recordnumber: LONGINT;
  1360. 1323 oldsafety,
  1361. 1324 oldexclusive:BOOLEAN;
  1362. 1325 FileError: StringIO.ErrorMessage;
  1363. 1326
  1364. 1327 BEGIN
  1365. 1328 IF NOT OpenDBF(ndx^.alias) THEN
  1366. 1329 WARN('Unable to open DBFile in BuildCompIndex');
  1367. 1330 END;
  1368. 1331 CloseIndex(ndx);
  1369. 1332 IF ndx^.Init#InitCode
  1370. 1333 THEN
  1371. 1334 WARN('Uninitalized DBIndex in BuildCompIndex');
  1372. 1335 END;
  1373. 1336 InitPosarray(ndx);
  1374. 1337 (* open exclusive *)
  1375. 1338 (* create if the file does not exist; truncate if it does exist *)
  1376. 1339 FileError := FAPI.DOSOPEN( ADR(ndx^.name),
  1377. 1340 ADR(ndx^.f), ADR(ActionTaken), VAL(LONGINT,1024),
  1378. 1341 FAPI.FILE_NORMAL,CARDINAL( {1,4}),CARDINAL( {1,4}),
  1379. 1342 VAL(LONGINT,0) );
  1380. 1343 IF FileError#0 THEN RETURN FileError END;
  1381. 1344 Fill(ADR(ndx^.Header),SIZE(ndx^.Header),0);
  1382. 1345 olddbbuffersize:=BufferSize(ndx^.alias);
  1383. 1346 oldbuffsize:=ndx^.buffsize;
  1384. 1347 oldsafety := ndx^.Safety;
  1385. 1348 oldexclusive:=ndx^.Exclusive;
  1386. 1349 SetDBBuffer( ndx^.alias,32000 );
  1387. 1350 IF ndx^.buffsize<400 THEN SetIndexBuffers(ndx,400) END;
  1388. 1351 WITH ndx^ DO
  1389. 1352 FOR i:=0 TO (Bins-1) DO
  1390. 1353 Hash[i]:=NIL;
  1391. 1354 END;
  1392. 1355 Safety:=FALSE;
  1393. 1356 Exclusive:=TRUE;
  1394. 1357 Assign(keyexp,Header.KeyExpression);
  1395. 1358 CrunchBlanks(Header.KeyExpression);
  1396. 1359 CAPstr(Header.KeyExpression);
  1397. 1360 KeyNumber := PosOfField(alias,Header.KeyExpression);
  1398. 1361 Append(Header.KeyExpression,' ');(* do this to mimic dbase3 *)
  1399. 1362 Header.rootptr := VAL(LONGINT,1); (* the root begins as the second block *)
  1400. 1363 (* The anchor node is 0 *)
  1401. 1364 Header.NumType := (type#'C');
  1402. 1365 IF type#'C'
  1403. 1366 THEN
  1404. 1367 Header.keylength:=8;
  1405. 1368 Header.entrylength :=16;
  1406. 1369 ELSE
  1407. 1370 Header.keylength := size;
  1408. 1371 Header.entrylength := Header.keylength + 2 * RecNumLen+1;
  1409. 1372 (*add 1 and make even to mimic dbase3 *)
  1410. 1373 IF ODD(Header.entrylength) THEN INC(Header.entrylength) END;
  1411. 1374 END;
  1412. 1375
  1413. 1376 Header.keyspernode := (NodeSize - 8) DIV (Header.entrylength);
  1414. 1377 (* a key 'entry' is made up of a pointer to a lower node and a
  1415. 1378 record number in addition to the key value . After the last key
  1416. 1379 entry there is a pointer to a lowerlevel node containing keys with
  1417. 1380 values greater than or equal to the the value of the key in the
  1418. 1381 last key entry *)
  1419. 1382 Header.nextfreenode := VAL(LONGINT,2);
  1420. 1383 open := TRUE;
  1421. 1384 depth := 0;
  1422. 1385 END;
  1423. 1386 InitNode(worknode);
  1424. 1387 WriteNode(ndx, VAL(LONGINT,1), worknode);
  1425. 1388 recordnumber := VAL(LONGINT,1);
  1426. 1389 WHILE recordnumber <= NumberRecords(ndx^.alias) DO
  1427. 1390 ReadDBRec(ndx^.alias, recordnumber);
  1428. 1391 (* change by ed ross*)
  1429. 1392 IF ndx^.includedeleted OR NOT Deleted(ndx^.alias)
  1430. 1393 THEN
  1431. 1394 AddRecord(ndx^.alias, ndx);
  1432. 1395 END;
  1433. 1396 (* * *End of change by ed *)
  1434. 1397 INC(recordnumber);
  1435. 1398 END;
  1436. 1399 CloseIndex(ndx);
  1437. 1400 ndx^.Exclusive:=oldexclusive;
  1438. 1401 ndx^.Safety:=oldsafety;
  1439. 1402 ndx^.buffsize:= oldbuffsize;
  1440. 1403 SetIndexBuffers(ndx,oldbuffsize);
  1441. 1404 SetDBBuffer( ndx^.alias,olddbbuffersize );
  1442. 1405 RETURN 0;
  1443. 1406 END BuildCompIndex;
  1444. 1407
  1445. 1408 PROCEDURE GoTop(ndx: DBIndex);
  1446. 1409 VAR nextnodeptr: LONGINT;
  1447. 1410 level: CARDINAL;
  1448. 1411 BEGIN
  1449. 1412 IF OpenIndex(ndx)=FALSE
  1450. 1413 THEN
  1451. 1414 WARN('Error opening Index in GoTop');
  1452. 1415 END;
  1453. 1416 EnterLock(ndx);
  1454. 1417 level := 0;
  1455. 1418 ReadIntoArray(ndx, ndx^.Header.rootptr, level);
  1456. 1419 Move(ADR(ndx^.posarray[level].buffer^.node[4]), ADR(nextnodeptr), 4);
  1457. 1420 (* all searches commence with the root *)
  1458. 1421 ndx^.posarray[level].keynum := FirstKey;
  1459. 1422 WHILE nextnodeptr#VAL(LONGINT,0) DO
  1460. 1423 INC(level);
  1461. 1424 ReadIntoArray(ndx, nextnodeptr, level);
  1462. 1425 ndx^.posarray[level].keynum := FirstKey;
  1463. 1426 Move(ADR(ndx^.posarray[level].buffer^.node[4]), ADR(nextnodeptr), 4);
  1464. 1427 END;
  1465. 1428 ndx^.currentkey:=GetKeyPtr(ndx^.posarray[level].buffer^.node, ndx, FirstKey);
  1466. 1429 ndx^.depth:=level;
  1467. 1430 ExitLock(ndx);
  1468. 1431 END GoTop;
  1469. 1432
  1470. 1433 PROCEDURE GoBottom( ndx: DBIndex);
  1471. 1434 VAR
  1472. 1435 level: CARDINAL;
  1473. 1436 BEGIN
  1474. 1437 IF OpenIndex(ndx)=FALSE
  1475. 1438 THEN
  1476. 1439 WARN('Error opening Index in GoBottom');
  1477. 1440 END;
  1478. 1441 EnterLock(ndx);
  1479. 1442 level := 0;
  1480. 1443 ReadIntoArray(ndx, ndx^.Header.rootptr, level);
  1481. 1444 ndx^.currentkey:=GetKeyPtr(ndx^.posarray[level].buffer^.node, ndx,
  1482. 1445 ORD(ndx^.posarray[level].buffer^.node[0]));
  1483. 1446 (* all searches commence with the root *)
  1484. 1447 ndx^.posarray[level].keynum := ORD(ndx^.posarray[level].buffer^.node[0]);
  1485. 1448 WHILE ndx^.currentkey^.lowernode # VAL(LONGINT,0) DO
  1486. 1449 INC(level);
  1487. 1450 ReadIntoArray(ndx, ndx^.currentkey^.lowernode, level);
  1488. 1451 ndx^.posarray[level].keynum := ORD(ndx^.posarray[level].buffer^.node[0]);
  1489. 1452 ndx^.currentkey:=GetKeyPtr(ndx^.posarray[level].buffer^.node, ndx,
  1490. 1453 ORD(ndx^.posarray[level].buffer^.node[0]));
  1491. 1454 END;
  1492. 1455 ndx^.posarray[level].keynum := ORD(ndx^.posarray[level].buffer^.node[0])-1;
  1493. 1456 ndx^.currentkey:=GetKeyPtr(ndx^.posarray[level].buffer^.node, ndx,
  1494. 1457 ORD(ndx^.posarray[level].buffer^.node[0])-1 );
  1495. 1458 ndx^.depth:=level;
  1496. 1459 ExitLock(ndx);
  1497. 1460 END GoBottom;
  1498. 1461
  1499. 1462
  1500. 1463 PROCEDURE AddToUpdateList( alias: DBFile; ndx:
  1501. 1464 DBIndex);
  1502. 1465 BEGIN
  1503. 1466 ndx^.UpdateList:=IndexList(alias);
  1504. 1467 SetIndexList(alias,ndx);
  1505. 1468
  1506. 1469 END AddToUpdateList;
  1507. 1470
  1508. 1471
  1509. 1472 PROCEDURE UpdateDBIndxes(alias:DBFile);
  1510. 1473 VAR
  1511. 1474 ndx:DBIndex;
  1512. 1475
  1513. 1476 PROCEDURE Update ;
  1514. 1477 VAR
  1515. 1478 NewKey,OldKey:ARRAY[0..MaxField-1] OF CHAR;
  1516. 1479 found:BOOLEAN;
  1517. 1480 num:LONGINT;
  1518. 1481
  1519. 1482 PROCEDURE KeyLocatedC():BOOLEAN ;
  1520. 1483 VAR
  1521. 1484 found:BOOLEAN;
  1522. 1485 BEGIN
  1523. 1486 FindPositionCh(ndx,OldKey,found);
  1524. 1487 LOOP
  1525. 1488 IF NOT Equal(OldKey,ndx^.currentkey^.value)
  1526. 1489 THEN
  1527. 1490 RETURN FALSE;
  1528. 1491 END;
  1529. 1492 IF (Record(alias) = ndx^.currentkey^.recordnum)
  1530. 1493 THEN
  1531. 1494 RETURN TRUE;
  1532. 1495 END;
  1533. 1496 IF NOT NextRecord(ndx,num)
  1534. 1497 THEN
  1535. 1498 RETURN FALSE;
  1536. 1499 END;
  1537. 1500 END;
  1538. 1501 END KeyLocatedC ;
  1539. 1502
  1540. 1503 PROCEDURE KeyLocatedN():BOOLEAN ;
  1541. 1504 VAR
  1542. 1505 found:BOOLEAN;
  1543. 1506 key:Real8;
  1544. 1507 BEGIN
  1545. 1508 IF NOT StrToReal(OldKey, 0,key) THEN key:=0.0 END;
  1546. 1509 FindPositionN(ndx,OldKey,found);
  1547. 1510 LOOP
  1548. 1511 IF ndx^.numkey^.key # key
  1549. 1512 THEN
  1550. 1513 RETURN FALSE;
  1551. 1514 END;
  1552. 1515 IF (Record(alias) = ndx^.currentkey^.recordnum)
  1553. 1516 THEN
  1554. 1517 RETURN TRUE;
  1555. 1518 END;
  1556. 1519 IF NOT NextRecord(ndx,num)
  1557. 1520 THEN
  1558. 1521 RETURN FALSE;
  1559. 1522 END;
  1560. 1523 END;
  1561. 1524 END KeyLocatedN ;
  1562. 1525
  1563. 1526 BEGIN
  1564. 1527 IF NOT Appending(alias)
  1565. 1528 THEN
  1566. 1529 SetRecordMode(alias,ModBase3.Buffer);
  1567. 1530 ndx^.KeyProc(alias,ndx,OldKey);
  1568. 1531 SetRecordMode(alias,ModBase3.CurrentRec);
  1569. 1532 ndx^.KeyProc(alias,ndx,NewKey);
  1570. 1533 (* * * * * * * * * Changed by ed - delete index if deleting record* * * *)
  1571. 1534 IF ndx^.includedeleted OR NOT Deleted(alias)
  1572. 1535 THEN IF Equal(OldKey,NewKey)
  1573. 1536 THEN
  1574. 1537 RETURN
  1575. 1538 END;
  1576. 1539 END;
  1577. 1540 IF Record(alias) # ndx^.currentkey^.recordnum
  1578. 1541 THEN
  1579. 1542 (* find and delete old key if exists *)
  1580. 1543 IF ndx^.Header.NumType
  1581. 1544 THEN
  1582. 1545 found:=KeyLocatedN();
  1583. 1546 ELSE
  1584. 1547 found:=KeyLocatedC();
  1585. 1548 END;
  1586. 1549 ELSE
  1587. 1550 found :=TRUE;
  1588. 1551 END;
  1589. 1552 IF found
  1590. 1553 THEN
  1591. 1554 DeleteCurrentEntry(ndx);
  1592. 1555 ELSE
  1593. 1556 found:=FALSE; (* debugger trap *)
  1594. 1557 END;
  1595. 1558 END;
  1596. 1559 (* * * * * * * * Changed by Ed - same as above ** ** * * * *)
  1597. 1560 IF ndx^.includedeleted OR NOT Deleted(alias)
  1598. 1561 THEN
  1599. 1562 AddRecord(alias,ndx);
  1600. 1563 END;
  1601. 1564 END Update;
  1602. 1565
  1603. 1566 BEGIN
  1604. 1567 (* Nul Value of IndexList should be checked in Modbase *)
  1605. 1568 ndx:=IndexList(alias);
  1606. 1569 WHILE ndx#NIL DO
  1607. 1570 IF OpenIndex(ndx)=FALSE
  1608. 1571 THEN
  1609. 1572 WARN('Error opening Index in UpdateDBIndxes');
  1610. 1573 END;
  1611. 1574 EnterLock(ndx);
  1612. 1575 Update;
  1613. 1576 ExitLock(ndx);
  1614. 1577 ndx:=ndx^.UpdateList;
  1615. 1578 END (* while *);
  1616. 1579 END UpdateDBIndxes;
  1617. 1580
  1618. 1581 PROCEDURE UpdateUnique( alias: DBFile; ndx: DBIndex):BOOLEAN;
  1619. 1582 VAR
  1620. 1583 NewKey,OldKey:ARRAY[0..MaxField-1] OF CHAR;
  1621. 1584 found:BOOLEAN;
  1622. 1585
  1623. 1586 BEGIN
  1624. 1587 IF OpenIndex(ndx)=FALSE
  1625. 1588 THEN
  1626. 1589 WARN('Error opening Index in UpdateUnique');
  1627. 1590 END;
  1628. 1591 EnterLock(ndx);
  1629. 1592 SetRecordMode(alias,ModBase3.CurrentRec);
  1630. 1593 ndx^.KeyProc(alias,ndx,NewKey);
  1631. 1594 IF NOT Appending(alias)
  1632. 1595 THEN
  1633. 1596 SetRecordMode(alias,ModBase3.Buffer);
  1634. 1597 ndx^.KeyProc(alias,ndx,OldKey);
  1635. 1598 SetRecordMode(alias,ModBase3.CurrentRec);
  1636. 1599 IF Equal(OldKey,NewKey)
  1637. 1600 THEN
  1638. 1601 ExitLock(ndx);
  1639. 1602 RETURN TRUE;
  1640. 1603 END;
  1641. 1604 END;
  1642. 1605 IF ndx^.Header.NumType
  1643. 1606 THEN
  1644. 1607 FindPositionN(ndx,NewKey,found);
  1645. 1608 ELSE
  1646. 1609 FindPositionCh(ndx,NewKey,found);
  1647. 1610 END;
  1648. 1611 ExitLock(ndx);
  1649. 1612 RETURN NOT found;
  1650. 1613 END UpdateUnique;
  1651. 1614
  1652. 1615
  1653. 1616 PROCEDURE SetSafetyOn( ndx: DBIndex);
  1654. 1617 BEGIN
  1655. 1618 UpdateIndex(ndx);
  1656. 1619 ndx^.Safety:=TRUE;
  1657. 1620 END SetSafetyOn;
  1658. 1621
  1659. 1622
  1660. 1623 PROCEDURE SetSafetyOff( ndx: DBIndex);
  1661. 1624 BEGIN
  1662. 1625 ndx^.Safety:=FALSE;
  1663. 1626
  1664. 1627 END SetSafetyOff;
  1665. 1628
  1666. 1629 PROCEDURE SetIndexBuffers( ndx: DBIndex;Buffers:CARDINAL);
  1667. 1630 VAR
  1668. 1631 buffer:IndexBuffer;
  1669. 1632 BEGIN
  1670. 1633 WITH ndx^ DO
  1671. 1634 buffsize := Max(Buffers,depth+6);
  1672. 1635 buffer:=last;
  1673. 1636 WHILE buffsize<currsize DO
  1674. 1637 WHILE buffer^.Lock DO
  1675. 1638 buffer:=buffer^.prev;
  1676. 1639 END;
  1677. 1640 IF buffer^.NeedToWrite
  1678. 1641 THEN
  1679. 1642 WriteNode(ndx,buffer^.number,buffer^.node);
  1680. 1643 END;
  1681. 1644 RemoveBuffer(ndx,buffer);
  1682. 1645 RemoveFromTable(ndx,buffer);
  1683. 1646 DosDealloc(buffer,SIZE(buffer^));
  1684. 1647 END;
  1685. 1648 END;
  1686. 1649 END SetIndexBuffers;
  1687. 1650
  1688. 1651
  1689. 1652 PROCEDURE DisposeIndex(VAR ndx: DBIndex);
  1690. 1653 BEGIN
  1691. 1654 CloseIndex(ndx);
  1692. 1655 DosDealloc(ndx,SIZE(ndx^));
  1693. 1656 ndx := NIL;
  1694. 1657 END DisposeIndex;
  1695. 1658
  1696. 1659 PROCEDURE CurrentKeyCh( ndx: DBIndex;VAR val:ARRAY OF CHAR);
  1697. 1660 BEGIN
  1698. 1661 Assign(ndx^.currentkey^.value,val);
  1699. 1662 END CurrentKeyCh;
  1700. 1663
  1701. 1664 PROCEDURE CurrentKeyN( ndx: DBIndex):Real8;
  1702. 1665 BEGIN
  1703. 1666 RETURN ndx^.numkey^.key;
  1704. 1667
  1705. 1668 END CurrentKeyN;
  1706. 1669
  1707. 1670
  1708. 1671 PROCEDURE CurrentRec( ndx: DBIndex):LONGINT;
  1709. 1672 BEGIN
  1710. 1673 RETURN ndx^.currentkey^.recordnum;
  1711. 1674 END CurrentRec;
  1712. 1675
  1713. 1676 PROCEDURE NumKeyType( ndx: DBIndex):BOOLEAN;
  1714. 1677 BEGIN
  1715. 1678 RETURN ndx^.Header.NumType;
  1716. 1679 END NumKeyType;
  1717. 1680
  1718. 1681 PROCEDURE KeyLength( ndx: DBIndex):CARDINAL;
  1719. 1682 BEGIN
  1720. 1683 RETURN ndx^.Header.keylength;
  1721. 1684 END KeyLength;
  1722. 1685
  1723. 1686 PROCEDURE InitCompIndex(indexname: ARRAY OF CHAR; VAR
  1724. 1687 ndx: DBIndex; alias:DBFile;Key :KeyProcedure; buffersize: CARDINAL
  1725. 1688 ; safety,IncludeDeleted,exclusive:BOOLEAN);
  1726. 1689 VAR i:CARDINAL;
  1727. 1690 BEGIN
  1728. 1691 DosAlloc(ndx,SIZE(ndx^));
  1729. 1692 ndx^.alias:=alias;
  1730. 1693 WITH ndx^ DO
  1731. 1694 Init:=InitCode;
  1732. 1695 Assign(indexname,name);
  1733. 1696 Locked:=0;
  1734. 1697 includedeleted:=IncludeDeleted;
  1735. 1698 Exclusive:=exclusive OR Locks.ExclusiveOnly;
  1736. 1699 open:=FALSE;
  1737. 1700 depth:=0;
  1738. 1701 KeyProc:=Key ;
  1739. 1702 buffsize:=buffersize;
  1740. 1703 Safety:=safety;
  1741. 1704 first:=NIL;
  1742. 1705 last:=NIL;
  1743. 1706 currsize := 0;
  1744. 1707 UpdateList:=NIL;
  1745. 1708 END;
  1746. 1709 END InitCompIndex;
  1747. 1710
  1748. 1711 PROCEDURE InitIndex(indexname: ARRAY OF CHAR; VAR
  1749. 1712 ndx: DBIndex; alias:DBFile; buffersize: CARDINAL;
  1750. 1713 safety, IncludeDeleted,exclusive:BOOLEAN);
  1751. 1714 BEGIN
  1752. 1715 InitCompIndex(indexname,ndx,alias,DefaultKeyProcedure,buffersize,safety,
  1753. 1716 IncludeDeleted,exclusive);
  1754. 1717 END InitIndex;
  1755. 1718
  1756. 1719
  1757. 1720
  1758. 1721
  1759. 1722 PROCEDURE OpenIndex( ndx: DBIndex):BOOLEAN;
  1760. 1723
  1761. 1724 VAR
  1762. 1725 str:ARRAY[0..387] OF CHAR;
  1763. 1726 ActionTaken,
  1764. 1727 i,res:CARDINAL;
  1765. 1728 filemode:BITSET;
  1766. 1729 BEGIN
  1767. 1730 IF ndx = NIL
  1768. 1731 THEN
  1769. 1732 WARN('Unititalized ndx in OpenIndex');
  1770. 1733 RETURN FALSE;
  1771. 1734 END;
  1772. 1735 IF ndx^.Init=InitCode
  1773. 1736 THEN
  1774. 1737 IF ndx^.open
  1775. 1738 THEN
  1776. 1739 RETURN TRUE;
  1777. 1740 END;
  1778. 1741 ELSE
  1779. 1742 WARN('Uninitalized ndx in OpenIndex');
  1780. 1743 END;
  1781. 1744 ndx^.open := FALSE;
  1782. 1745 (* Open if it does exist; fail if it doesn't *)
  1783. 1746 IF ndx^.Exclusive THEN
  1784. 1747 filemode:={1,4}
  1785. 1748 ELSE
  1786. 1749 filemode:={1,6} (* allow all *)
  1787. 1750 END;
  1788. 1751 res := FAPI.DOSOPEN( ADR(ndx^.name),
  1789. 1752 ADR(ndx^.f), ADR(ActionTaken), VAL(LONGINT,0), FAPI.FILE_NORMAL,
  1790. 1753 CARDINAL( {0}), CARDINAL(filemode), VAL(LONGINT,0) );
  1791. 1754
  1792. 1755 IF res # StringIO.NoError THEN
  1793. 1756 RETURN FALSE;
  1794. 1757 ELSE
  1795. 1758 IF Locks.NoLocking(ndx^.f) THEN ndx^.Exclusive:=TRUE END;
  1796. 1759 InitPosarray(ndx);
  1797. 1760 EnterLock(ndx);
  1798. 1761 IF HandleIO.BlockRead(ndx^.f,ADR(ndx^.Header),SIZE(ndx^.Header))#
  1799. 1762 StringIO.NoError
  1800. 1763 THEN
  1801. 1764 ExitLock(ndx);
  1802. 1765 StringIO.PrintMessage(HandleIO.CloseHandle(ndx^.f));
  1803. 1766 RETURN FALSE;
  1804. 1767 END;
  1805. 1768 WITH ndx^ DO
  1806. 1769 FOR i:=0 TO (Bins-1) DO
  1807. 1770 Hash[i]:=NIL;
  1808. 1771 END;
  1809. 1772 Assign(Header.KeyExpression,str);
  1810. 1773 CrunchBlanks(str);
  1811. 1774 CAPstr(str);
  1812. 1775 KeyNumber:=PosOfField(ndx^.alias,str);
  1813. 1776 SetIndexBuffers(ndx,buffsize);
  1814. 1777 open := TRUE;
  1815. 1778 END;
  1816. 1779 GoTop(ndx);
  1817. 1780 ExitLock(ndx);
  1818. 1781 END; (* IF *)
  1819. 1782 RETURN TRUE;
  1820. 1783 END OpenIndex;
  1821. 1784
  1822. 1785
  1823. 1786 PROCEDURE NextRecord( ndx: DBIndex;
  1824. 1787 VAR recno: LONGINT): BOOLEAN;
  1825. 1788
  1826. 1789 PROCEDURE NextEntry(ndx: DBIndex; level: CARDINAL): BOOLEAN;
  1827. 1790
  1828. 1791 VAR
  1829. 1792 anotherkey: BOOLEAN;
  1830. 1793 key:KeyPointer;
  1831. 1794 factor:CARDINAL;
  1832. 1795 BEGIN
  1833. 1796 key:=ADR(ndx^.currentkey);
  1834. 1797 LOOP
  1835. 1798 IF level=ndx^.depth (* ok depth becuse all of loop is in same route*)
  1836. 1799 THEN
  1837. 1800 factor:=1;
  1838. 1801 ELSE
  1839. 1802 factor:=0;
  1840. 1803 END;
  1841. 1804 anotherkey := ndx^.posarray[level].keynum <
  1842. 1805 ( ORD(ndx^.posarray[level].buffer^.node[0]) - factor);
  1843. 1806 IF anotherkey THEN
  1844. 1807 (* there is another entry in the node *)
  1845. 1808 (* note that the first entry is 0, so the number of the last entry
  1846. 1809 is one less than the number of keys in the node *)
  1847. 1810 WITH ndx^.posarray[level] DO
  1848. 1811 INC(keynum);
  1849. 1812 key:=GetKeyPtr(buffer^.node, ndx, keynum);
  1850. 1813 EXIT;
  1851. 1814 END;
  1852. 1815 ELSE
  1853. 1816 IF level = 0 THEN
  1854. 1817 EXIT
  1855. 1818 ELSE
  1856. 1819 DEC(level)
  1857. 1820 END;
  1858. 1821 END;
  1859. 1822 END; (* LOOP *)
  1860. 1823 IF anotherkey THEN
  1861. 1824 LOOP
  1862. 1825 IF key^.lowernode#VAL(LONGINT,0) THEN (* node is not a leaf node *)
  1863. 1826 INC(level);
  1864. 1827 ReadIntoArray(ndx, key^.lowernode, level);
  1865. 1828 WITH ndx^.posarray[level] DO
  1866. 1829 keynum := FirstKey;
  1867. 1830 key:=GetKeyPtr(buffer^.node, ndx, FirstKey);
  1868. 1831 END;
  1869. 1832 ELSE
  1870. 1833 EXIT
  1871. 1834 END;
  1872. 1835 END; (* LOOP2 *)
  1873. 1836 ndx^.depth:=level;
  1874. 1837 ndx^.currentkey:=key;
  1875. 1838 RETURN TRUE;
  1876. 1839 ELSE
  1877. 1840 ndx^.depth:=level;
  1878. 1841 ndx^.currentkey:=key;
  1879. 1842 RETURN FALSE;
  1880. 1843 END;
  1881. 1844 END NextEntry;
  1882. 1845
  1883. 1846 BEGIN
  1884. 1847 IF OpenIndex(ndx)=FALSE
  1885. 1848 THEN
  1886. 1849 WARN('Error opening Index in NextRecord');
  1887. 1850 END;
  1888. 1851 EnterLock(ndx);
  1889. 1852 IF NextEntry(ndx, ndx^.depth) THEN
  1890. 1853 recno := ndx^.currentkey^.recordnum;
  1891. 1854 ExitLock(ndx);
  1892. 1855 RETURN TRUE
  1893. 1856 ELSE
  1894. 1857 ExitLock(ndx);
  1895. 1858 RETURN FALSE
  1896. 1859 END;
  1897. 1860 END NextRecord;
  1898. 1861
  1899. 1862
  1900. 1863 PROCEDURE PrevRecord( ndx: DBIndex;
  1901. 1864 VAR recno: LONGINT): BOOLEAN;
  1902. 1865
  1903. 1866 PROCEDURE PrevEntry( ndx: DBIndex; level: CARDINAL): BOOLEAN;
  1904. 1867
  1905. 1868 VAR anotherkey: BOOLEAN;
  1906. 1869 lastkey: CARDINAL;
  1907. 1870 key:KeyPointer;
  1908. 1871 BEGIN
  1909. 1872 key:=ADR(ndx^.currentkey);
  1910. 1873 LOOP
  1911. 1874 anotherkey := ndx^.posarray[level].keynum > 0;
  1912. 1875 IF anotherkey THEN
  1913. 1876 (* there is another entry in the node *)
  1914. 1877 (* note that the first entry is 0, so the number of the last entry
  1915. 1878 is one less than the number of keys in the node *)
  1916. 1879 WITH ndx^.posarray[level] DO
  1917. 1880 DEC(keynum);
  1918. 1881 key:=GetKeyPtr(buffer^.node, ndx, keynum);
  1919. 1882 END;
  1920. 1883 EXIT;
  1921. 1884 ELSE
  1922. 1885 IF level = 0 THEN
  1923. 1886 EXIT
  1924. 1887 ELSE
  1925. 1888 DEC(level)
  1926. 1889 END;
  1927. 1890 END;
  1928. 1891 END; (* LOOP *)
  1929. 1892 IF anotherkey THEN
  1930. 1893 LOOP
  1931. 1894 IF key^.lowernode#VAL(LONGINT,0) THEN (* node is not a leaf node *)
  1932. 1895 INC(level);
  1933. 1896 ReadIntoArray(ndx, key^.lowernode, level);
  1934. 1897 WITH ndx^.posarray[level] DO
  1935. 1898 lastkey := ORD(buffer^.node[0]);
  1936. 1899 keynum := lastkey;
  1937. 1900 key:=GetKeyPtr(buffer^.node, ndx, lastkey);
  1938. 1901 IF key^.lowernode=VAL(LONGINT,0)
  1939. 1902 THEN (* backup one*)
  1940. 1903 DEC(lastkey);
  1941. 1904 keynum := lastkey;
  1942. 1905 key:=GetKeyPtr(buffer^.node, ndx, lastkey);
  1943. 1906 END;
  1944. 1907 END;
  1945. 1908 ELSE
  1946. 1909 EXIT
  1947. 1910 END;
  1948. 1911 END; (* LOOP2 *)
  1949. 1912 ndx^.depth:=level;
  1950. 1913 ndx^.currentkey:=key;
  1951. 1914 RETURN TRUE;
  1952. 1915 ELSE
  1953. 1916 ndx^.depth:=level;
  1954. 1917 ndx^.currentkey:=key;
  1955. 1918 RETURN FALSE;
  1956. 1919 END;
  1957. 1920 END PrevEntry;
  1958. 1921 BEGIN
  1959. 1922 IF OpenIndex(ndx)=FALSE
  1960. 1923 THEN
  1961. 1924 WARN('Error opening Index in PrevRecord');
  1962. 1925 END;
  1963. 1926 EnterLock(ndx);
  1964. 1927 IF PrevEntry(ndx, ndx^.depth) THEN
  1965. 1928 recno := ndx^.currentkey^.recordnum;
  1966. 1929 ExitLock(ndx);
  1967. 1930 RETURN TRUE
  1968. 1931 ELSE
  1969. 1932 ExitLock(ndx);
  1970. 1933 RETURN FALSE
  1971. 1934 END;
  1972. 1935 END PrevRecord;
  1973. 1936
  1974. 1937 PROCEDURE UpdateIndex( ndx :DBIndex);
  1975. 1938
  1976. 1939 BEGIN
  1977. 1940 IF ndx^.open
  1978. 1941 THEN
  1979. 1942 EnterLock(ndx);
  1980. 1943 UpdateIndexHeader(ndx);
  1981. 1944 HandleIO.UpdateDisk(ndx^.f);
  1982. 1945 ExitLock(ndx);
  1983. 1946 END;
  1984. 1947 END UpdateIndex;
  1985. 1948
  1986. 1949 PROCEDURE CloseIndex( ndx: DBIndex);
  1987. 1950 VAR
  1988. 1951 buffer:IndexBuffer;
  1989. 1952 FileError: StringIO.ErrorMessage;
  1990. 1953 BEGIN
  1991. 1954 IF ndx = NIL
  1992. 1955 THEN
  1993. 1956 RETURN;
  1994. 1957 END;
  1995. 1958 IF NOT ndx^.open
  1996. 1959 THEN
  1997. 1960 RETURN;
  1998. 1961 END;
  1999. 1962 IF ndx^.Exclusive AND NOT ndx^.Safety
  2000. 1963 THEN
  2001. 1964 UpdateIndexHeader( ndx );
  2002. 1965 END;
  2003. 1966 FileError := HandleIO.CloseHandle(ndx^.f);
  2004. 1967 ndx^.open := FALSE;
  2005. 1968 WHILE ndx^.currsize#0 DO
  2006. 1969 buffer:=ndx^.last;
  2007. 1970 RemoveBuffer(ndx,buffer);
  2008. 1971 DosDealloc(buffer,SIZE(buffer^));
  2009. 1972 END;
  2010. 1973
  2011. 1974 END CloseIndex;
  2012. 1975
  2013. 1976 (* file locking procedures start here *)
  2014. 1977 PROCEDURE EnterLock( ndx:DBIndex);
  2015. 1978 VAR
  2016. 1979 realkey:Real8;
  2017. 1980 strkey:ARRAY[0..127] OF CHAR;
  2018. 1981 buffer:IndexBuffer;
  2019. 1982 ok,found:BOOLEAN;
  2020. 1983 i,
  2021. 1984 code,
  2022. 1985 Old :CARDINAL;
  2023. 1986 key,OldRecord:LONGINT;
  2024. 1987 BEGIN
  2025. 1988 (* lock file if needed *)
  2026. 1989 INC(ndx^.Locked);
  2027. 1990 IF (ndx^.Locked>1) OR ndx^.Exclusive THEN RETURN END;
  2028. 1991 (* read Header*)
  2029. 1992 StringIO.PrintMessage(Locks.LockFileRetry(ndx^.f,100,ndx^.name));
  2030. 1993 ndx^.Changed:=FALSE;
  2031. 1994 IF ndx^.open=FALSE THEN RETURN END;(* this should only be in open index *)
  2032. 1995 Old:=ndx^.Header.Flag;
  2033. 1996 ReadHeader(ndx);
  2034. 1997 IF Old=ndx^.Header.Flag THEN RETURN END;
  2035. 1998 OldRecord:=ndx^.currentkey^.recordnum;
  2036. 1999 IF ndx^.Header.NumType
  2037. 2000 THEN
  2038. 2001 realkey:=ndx^.numkey^.key;
  2039. 2002 ELSE
  2040. 2003 Assign(ndx^.currentkey^.value,strkey);
  2041. 2004 END;
  2042. 2005 (* purge buffers*)
  2043. 2006 WHILE ndx^.currsize#0 DO
  2044. 2007 buffer:=ndx^.last; (* it is forbidden here to have unwritten data *)
  2045. 2008 IF buffer^.NeedToWrite THEN (* not needed when debugged *)
  2046. 2009 WARN('buffer not writen in EnterLock');
  2047. 2010 END;
  2048. 2011 RemoveBuffer(ndx,buffer);
  2049. 2012 RemoveFromTable(ndx,buffer);
  2050. 2013 DosDealloc(buffer,SIZE(buffer^));
  2051. 2014 END;
  2052. 2015 FOR i:= 0 TO ndx^.depth DO
  2053. 2016 ndx^.posarray[i].buffer:=NIL;
  2054. 2017 END;
  2055. 2018 IF ndx^.Header.NumType
  2056. 2019 THEN
  2057. 2020 FindPositionR(ndx,realkey,found);
  2058. 2021 ELSE
  2059. 2022 FindPositionCh(ndx,strkey,found);
  2060. 2023 END;
  2061. 2024 IF NOT found
  2062. 2025 THEN RETURN (* key must have been removed *)
  2063. 2026 END;
  2064. 2027 REPEAT
  2065. 2028 IF OldRecord=ndx^.currentkey^.recordnum
  2066. 2029 THEN RETURN END; (* we got it*)
  2067. 2030 found:=NextRecord(ndx,key);
  2068. 2031 IF ndx^.Header.NumType
  2069. 2032 THEN
  2070. 2033 ok:=(realkey=ndx^.numkey^.key);
  2071. 2034 ELSE
  2072. 2035 ok:=Equal(ndx^.currentkey^.value,strkey);
  2073. 2036 END;
  2074. 2037 UNTIL NOT found OR NOT ok;
  2075. 2038 found:=PrevRecord(ndx,key); (* goback one*)
  2076. 2039 END EnterLock;
  2077. 2040
  2078. 2041 PROCEDURE ExitLock( ndx:DBIndex);
  2079. 2042 VAR
  2080. 2043 code:CARDINAL;
  2081. 2044 BEGIN
  2082. 2045 DEC(ndx^.Locked);
  2083. 2046 (* If No change or exclusive *)
  2084. 2047 IF ndx^.Exclusive OR ( ndx^.Locked#0) THEN RETURN END;
  2085. 2048 IF ndx^.Changed
  2086. 2049 THEN
  2087. 2050 INC(ndx^.Header.Flag); (* indicate change *)
  2088. 2051 WriteHeader(ndx); (* write header *)
  2089. 2052 END; (* if ndx^ changed *)
  2090. 2053 code:=Locks.UnLockFile(ndx^.f);
  2091. 2054 IF code#0 THEN WARN('Lock error in ExitLock') END;
  2092. 2055 END ExitLock;
  2093. 2056
  2094. 2057 BEGIN;
  2095. 2058 UpDateIndexes:=UpdateDBIndxes;
  2096. 2059
  2097. 2060 END DBIndxes.
  2098. 2061
  2099. 36 errors