Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

798 lines
19 KiB

  1. #include "config.h"
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "daedef.h"
  5. #include "util.h"
  6. #include "pib.h"
  7. #include "page.h"
  8. #include "ssib.h"
  9. #include "fmp.h"
  10. #include "fucb.h"
  11. #include "stapi.h"
  12. #include "dirapi.h"
  13. #include "fcb.h"
  14. #include "fdb.h"
  15. #include "idb.h"
  16. #include "scb.h"
  17. #include "recapi.h"
  18. #include "recint.h"
  19. #include "nver.h"
  20. #include "logapi.h"
  21. #include "fileint.h"
  22. #include "sortapi.h"
  23. #include "fileapi.h"
  24. DeclAssertFile; /* Declare file name for assert macros */
  25. CRIT critTempDBName;
  26. static ULONG ulTempNum = 0;
  27. ULONG NEAR
  28. ulTempNameGen()
  29. { ULONG ulNum;
  30. SgSemRequest(critTempDBName);
  31. ulNum = ulTempNum++;
  32. SgSemRelease(critTempDBName);
  33. return(ulNum);
  34. }
  35. /*=================================================================
  36. ErrIsamSortMaterialize
  37. Description: Converts a SORT file into a temporary file so that it
  38. may be accessed using the normal file access functions.
  39. /* 1. create temporary table
  40. /* 2. use DIR operations to convert SORT data to FILE data
  41. /* 3. fake SORT cursor to be FILE cursor
  42. /* 4. close SORT cursor and return SORT resources
  43. /**/
  44. /*
  45. Parameters: FUCB *pfucbSort pointer to the FUCB for the sort file
  46. Return Value: standard error return
  47. Errors/Warnings:
  48. <List of any errors or warnings, with any specific circumstantial
  49. comments supplied on an as-needed-only basis>
  50. Side Effects:
  51. =================================================================*/
  52. ERR VTAPI
  53. ErrIsamSortMaterialize( PIB *ppib, FUCB *pfucbSort, BOOL fIndex )
  54. {
  55. ERR err;
  56. INT crun;
  57. INT irun;
  58. INT cPages;
  59. RUN *rgrun;
  60. FUCB *pfucbTable = pfucbNil;
  61. FCB *pfcbTable;
  62. FCB *pfcbSort;
  63. FDB *pfdb;
  64. IDB *pidb;
  65. BYTE szName[JET_cbNameMost+1];
  66. CheckPIB( ppib );
  67. CheckSort( ppib, pfucbSort );
  68. Assert( ppib->level < levelMax );
  69. Assert( pfucbSort->ppib == ppib );
  70. Assert( !( FFUCBIndex( pfucbSort ) ) );
  71. /* causes remaining runs to be flushed to disk
  72. /**/
  73. if ( FSCBInsert( pfucbSort->u.pscb ) )
  74. {
  75. CallR( ErrSORTEndRead( pfucbSort ) );
  76. }
  77. CallR( ErrDIRBeginTransaction( ppib ) );
  78. crun = pfucbSort->u.pscb->crun;
  79. if ( crun > 0 )
  80. {
  81. rgrun = pfucbSort->u.pscb->rgrun;
  82. for (irun = 0, cPages=0; irun < crun; irun++)
  83. {
  84. cPages += rgrun[irun].cbfRun;
  85. }
  86. }
  87. else
  88. {
  89. cPages = 4;
  90. }
  91. /* generate temporary file name
  92. /**/
  93. sprintf(szName, "TEMP%lu", ulTempNameGen());
  94. /* create table
  95. /**/
  96. Call( ErrFILECreateTable( ppib, dbidTemp, szName, 16, 100, &pfucbTable ) );
  97. /* move to DATA root
  98. /**/
  99. DIRGotoDataRoot( pfucbTable );
  100. pfcbSort = &(pfucbSort->u.pscb->fcb);
  101. pfcbTable = pfucbTable->u.pfcb;
  102. err = ErrSORTFirst( pfucbSort );
  103. if ( fIndex )
  104. {
  105. while ( err >= 0 )
  106. {
  107. Call( ErrDIRInsert( pfucbTable,
  108. &pfucbSort->lineData,
  109. &pfucbSort->keyNode,
  110. fDIRVersion | fDIRBackToFather ) );
  111. err = ErrSORTNext( pfucbSort );
  112. }
  113. }
  114. else
  115. {
  116. DBK dbk = 0;
  117. BYTE rgbDbk[4];
  118. KEY keyDbk;
  119. keyDbk.cb = sizeof(DBK);
  120. keyDbk.pb = rgbDbk;
  121. while ( err >= 0 )
  122. {
  123. keyDbk.pb[0] = (BYTE)(dbk >> 24);
  124. keyDbk.pb[1] = (BYTE)((dbk >> 16) & 0xff);
  125. keyDbk.pb[2] = (BYTE)((dbk >> 8) & 0xff);
  126. keyDbk.pb[3] = (BYTE)(dbk & 0xff);
  127. dbk++;
  128. Call( ErrDIRInsert( pfucbTable,
  129. &pfucbSort->lineData,
  130. &keyDbk,
  131. fDIRVersion | fDIRBackToFather ) );
  132. err = ErrSORTNext(pfucbSort);
  133. }
  134. pfcbTable->dbkMost = dbk;
  135. }
  136. if ( err < 0 && err != JET_errNoCurrentRecord )
  137. {
  138. goto HandleError;
  139. }
  140. Call( ErrDIRCommitTransaction( ppib ) );
  141. /* convert sort cursor into table cursor by changing flags.
  142. /**/
  143. Assert( pfcbTable->pfcbNextIndex == pfcbNil );
  144. Assert( pfcbTable->dbid == dbidTemp );
  145. pfcbTable->cbDensityFree = 0;
  146. pfcbTable->wFlags = fFCBTemporaryTable | fFCBClusteredIndex;
  147. /* switch sort and table FDP so FDP preserved and ErrFILECloseTable.
  148. /**/
  149. pfdb = (FDB *)pfcbSort->pfdb;
  150. pfcbSort->pfdb = pfcbTable->pfdb;
  151. pfcbTable->pfdb = pfdb;
  152. /* switch sort and table IDB so IDB preserved and ErrFILECloseTable,
  153. /* only if fIndex.
  154. /**/
  155. if ( fIndex )
  156. {
  157. pidb = pfcbSort->pidb;
  158. pfcbSort->pidb = pfcbTable->pidb;
  159. pfcbTable->pidb = pidb;
  160. }
  161. /* convert sort cursor flags to table flags, with fFUCBOrignallySort
  162. /**/
  163. Assert( pfucbSort->dbid == dbidTemp );
  164. Assert( pfucbSort->pfucbCurIndex == pfucbNil );
  165. FUCBSetIndex( pfucbSort );
  166. FUCBResetSort( pfucbSort );
  167. /* release SCB and close table cursor
  168. /**/
  169. SORTClosePscb( pfucbSort->u.pscb );
  170. FCBLink( pfucbSort, pfcbTable );
  171. CallS( ErrFILECloseTable( ppib, pfucbTable ) );
  172. pfucbTable = pfucbNil;
  173. /* move to the first record ignoring error if table empty
  174. /**/
  175. err = ErrIsamMove( ppib, pfucbSort, JET_MoveFirst, 0 );
  176. if ( err < 0 )
  177. {
  178. if ( err != JET_errNoCurrentRecord )
  179. goto HandleError;
  180. }
  181. Assert( err == JET_errSuccess || err == JET_errNoCurrentRecord );
  182. return err;
  183. HandleError:
  184. if ( pfucbTable != pfucbNil )
  185. CallS( ErrFILECloseTable( ppib, pfucbTable ) );
  186. CallS( ErrDIRRollback( ppib ) );
  187. return err;
  188. }
  189. /*=================================================================
  190. ErrIsamMove
  191. Description:
  192. Retrieves the first, last, (nth) next, or (nth) previous
  193. record from the specified file.
  194. Parameters:
  195. PIB *ppib PIB of user
  196. FUCB *pfucb FUCB for file
  197. LONG crow number of rows to move
  198. JET_GRBIT grbit options
  199. Return Value: standard error return
  200. Errors/Warnings:
  201. <List of any errors or warnings, with any specific circumstantial
  202. comments supplied on an as-needed-only basis>
  203. Side Effects:
  204. =================================================================*/
  205. ERR VTAPI ErrIsamMove( PIB *ppib, FUCB *pfucb, LONG crow, JET_GRBIT grbit )
  206. {
  207. ERR err = JET_errSuccess;
  208. FUCB *pfucb2ndIdx; // FUCB for secondary index (if any)
  209. FUCB *pfucbIdx; // FUCB of selected index (pri or sec)
  210. SRID srid; // bookmark of record
  211. DIB dib; // Information block for DirMan
  212. CheckPIB( ppib );
  213. CheckTable( ppib, pfucb );
  214. CheckNonClustered( pfucb );
  215. if ( FFUCBUpdatePrepared( pfucb ) )
  216. {
  217. CallR( ErrIsamPrepareUpdate( ppib, pfucb, JET_prepCancel ) );
  218. }
  219. #ifdef INPAGE
  220. /* check to see if search can cross page boundary
  221. /* and set flag accordingly.
  222. /**/
  223. if ( grbit & JET_bitMoveInPage )
  224. dib.fFlags = fDIRInPage;
  225. else
  226. dib.fFlags = fDIRNull;
  227. #else
  228. Assert( ( grbit & JET_bitMoveInPage ) == 0 );
  229. dib.fFlags = fDIRNull;
  230. #endif
  231. // Get secondary index FUCB if any
  232. pfucb2ndIdx = pfucb->pfucbCurIndex;
  233. if ( pfucb2ndIdx == pfucbNil )
  234. pfucbIdx = pfucb;
  235. else
  236. pfucbIdx = pfucb2ndIdx;
  237. if ( crow == JET_MoveLast )
  238. {
  239. DIRResetIndexRange( pfucb );
  240. dib.pos = posLast;
  241. dib.fFlags |= fDIRPurgeParent;
  242. /* move to DATA root
  243. /**/
  244. DIRGotoDataRoot( pfucbIdx );
  245. err = ErrDIRDown( pfucbIdx, &dib );
  246. }
  247. else if ( crow > 0 )
  248. {
  249. LONG crowT = crow;
  250. if ( ( grbit & JET_bitMoveKeyNE ) != 0 )
  251. dib.fFlags |= fDIRNeighborKey;
  252. // Move forward number of rows given
  253. while ( crowT-- > 0 )
  254. {
  255. err = ErrDIRNext( pfucbIdx, &dib );
  256. if (err < 0)
  257. break;
  258. }
  259. }
  260. else if ( crow == JET_MoveFirst )
  261. {
  262. DIRResetIndexRange( pfucb );
  263. dib.pos = posFirst;
  264. dib.fFlags |= fDIRPurgeParent;
  265. /* move to DATA root
  266. /**/
  267. DIRGotoDataRoot( pfucbIdx );
  268. err = ErrDIRDown( pfucbIdx, &dib );
  269. }
  270. else if ( crow == 0 )
  271. {
  272. err = ErrDIRGet( pfucb );
  273. }
  274. else
  275. {
  276. LONG crowT = crow;
  277. if ( ( grbit & JET_bitMoveKeyNE ) != 0)
  278. dib.fFlags |= fDIRNeighborKey;
  279. while ( crowT++ < 0 )
  280. {
  281. err = ErrDIRPrev( pfucbIdx, &dib );
  282. if ( err < 0 )
  283. break;
  284. }
  285. }
  286. /* if the movement was successful and a non-clustered index is
  287. /* in use, then position clustered index to record.
  288. /**/
  289. if ( err == JET_errSuccess && pfucb2ndIdx != pfucbNil && crow != 0 )
  290. {
  291. Assert( pfucb2ndIdx->lineData.pb != NULL );
  292. Assert( pfucb2ndIdx->lineData.cb >= sizeof(SRID) );
  293. srid = PcsrCurrent( pfucb2ndIdx )->item;
  294. DIRDeferGotoBookmark( pfucb, srid );
  295. Assert( PgnoOfSrid( srid ) != pgnoNull );
  296. }
  297. if ( err == JET_errSuccess )
  298. return err;
  299. if ( err == JET_errPageBoundary )
  300. return JET_errNoCurrentRecord;
  301. if ( crow > 0 )
  302. {
  303. PcsrCurrent(pfucbIdx)->csrstat = csrstatAfterLast;
  304. PcsrCurrent(pfucb)->csrstat = csrstatAfterLast;
  305. }
  306. else if ( crow < 0 )
  307. {
  308. PcsrCurrent(pfucbIdx)->csrstat = csrstatBeforeFirst;
  309. PcsrCurrent(pfucb)->csrstat = csrstatBeforeFirst;
  310. }
  311. switch ( err )
  312. {
  313. case JET_errRecordNotFound:
  314. err = JET_errNoCurrentRecord;
  315. case JET_errNoCurrentRecord:
  316. case JET_errRecordDeleted:
  317. break;
  318. default:
  319. PcsrCurrent( pfucbIdx )->csrstat = csrstatBeforeFirst;
  320. if ( pfucb2ndIdx != pfucbNil )
  321. PcsrCurrent( pfucb2ndIdx )->csrstat = csrstatBeforeFirst;
  322. }
  323. return err;
  324. }
  325. /*=================================================================
  326. ErrIsamSeek
  327. Description:
  328. Retrieve the record specified by the given key or the
  329. one just after it (SeekGT or SeekGE) or the one just
  330. before it (SeekLT or SeekLE).
  331. Parameters:
  332. PIB *ppib PIB of user
  333. FUCB *pfucb FUCB for file
  334. JET_GRBIT grbit grbit
  335. Return Value: standard error return
  336. Errors/Warnings:
  337. <List of any errors or warnings, with any specific circumstantial
  338. comments supplied on an as-needed-only basis>
  339. Side Effects:
  340. =================================================================*/
  341. ERR VTAPI ErrIsamSeek( PIB *ppib, FUCB *pfucb, JET_GRBIT grbit )
  342. {
  343. ERR err = JET_errSuccess;
  344. KEY key; // key
  345. KEY *pkey = &key; // pointer to the input key
  346. FUCB *pfucb2ndIdx; // pointer to index FUCB (if any)
  347. BOOL fFoundLess;
  348. SRID srid; // bookmark of record
  349. JET_GRBIT grbitMove = 0;
  350. CheckPIB( ppib );
  351. CheckTable( ppib, pfucb );
  352. CheckNonClustered( pfucb );
  353. if ( ! ( FKSPrepared( pfucb ) ) )
  354. {
  355. return(JET_errKeyNotMade);
  356. }
  357. /* Reset copy buffer status
  358. /**/
  359. if ( FFUCBUpdatePrepared( pfucb ) )
  360. {
  361. CallR( ErrIsamPrepareUpdate( ppib, pfucb, JET_prepCancel ) );
  362. }
  363. /* reset index range limit
  364. /**/
  365. DIRResetIndexRange( pfucb );
  366. /* ignore segment counter
  367. /**/
  368. pkey->pb = pfucb->pbKey + 1;
  369. pkey->cb = pfucb->cbKey - 1;
  370. pfucb2ndIdx = pfucb->pfucbCurIndex;
  371. if ( pfucb2ndIdx == pfucbNil )
  372. {
  373. err = ErrDIRDownFromDATA( pfucb, pkey );
  374. }
  375. else
  376. {
  377. Assert( FFUCBNonClustered( pfucb2ndIdx ) );
  378. err = ErrDIRDownFromDATA( pfucb2ndIdx, pkey );
  379. /* if the movement was successful and a non-clustered index is
  380. /* in use, then position clustered index to record.
  381. /**/
  382. if ( err == JET_errSuccess )
  383. {
  384. Assert(pfucb2ndIdx->lineData.pb != NULL);
  385. Assert(pfucb2ndIdx->lineData.cb >= sizeof(SRID));
  386. srid = PcsrCurrent( pfucb2ndIdx )->item;
  387. DIRDeferGotoBookmark( pfucb, srid );
  388. Assert( PgnoOfSrid( srid ) != pgnoNull );
  389. }
  390. }
  391. if ( err == JET_errSuccess && ( grbit & JET_bitSeekEQ ) != 0 )
  392. {
  393. /* found equal on seek equal. If index range grbit is
  394. /* set then set index range upper inclusive.
  395. /**/
  396. if ( grbit & JET_bitSetIndexRange )
  397. {
  398. CallR( ErrIsamSetIndexRange( ppib, pfucb, JET_bitRangeInclusive | JET_bitRangeUpperLimit ) );
  399. }
  400. /* reset key status.
  401. /**/
  402. KSReset( pfucb );
  403. return err;
  404. }
  405. /* reset key status.
  406. /**/
  407. KSReset( pfucb );
  408. /* remember if found less.
  409. /**/
  410. fFoundLess = ( err == wrnNDFoundLess );
  411. if ( err == wrnNDFoundLess || err == wrnNDFoundGreater )
  412. {
  413. err = JET_errRecordNotFound;
  414. }
  415. else if ( err < 0 )
  416. {
  417. PcsrCurrent( pfucb )->csrstat = csrstatBeforeFirst;
  418. if ( pfucb2ndIdx != pfucbNil )
  419. {
  420. PcsrCurrent( pfucb2ndIdx )->csrstat = csrstatBeforeFirst;
  421. }
  422. }
  423. #define bitSeekAll (JET_bitSeekEQ | JET_bitSeekGE | JET_bitSeekGT | \
  424. JET_bitSeekLE | JET_bitSeekLT)
  425. /* adjust currency for seek request.
  426. /**/
  427. switch ( grbit & bitSeekAll )
  428. {
  429. case JET_bitSeekEQ:
  430. return err;
  431. case JET_bitSeekGE:
  432. if ( err != JET_errRecordNotFound )
  433. return err;
  434. err = ErrIsamMove( ppib, pfucb, +1L, grbitMove );
  435. if ( err == JET_errNoCurrentRecord )
  436. return JET_errRecordNotFound;
  437. else
  438. return JET_wrnSeekNotEqual;
  439. case JET_bitSeekGT:
  440. if ( err < 0 && err != JET_errRecordNotFound )
  441. return err;
  442. if ( err >= 0 || fFoundLess )
  443. grbitMove |= JET_bitMoveKeyNE;
  444. err = ErrIsamMove( ppib, pfucb, +1L, grbitMove );
  445. if ( err == JET_errNoCurrentRecord )
  446. return JET_errRecordNotFound;
  447. else
  448. return err;
  449. case JET_bitSeekLE:
  450. if ( err != JET_errRecordNotFound )
  451. return err;
  452. err = ErrIsamMove( ppib, pfucb, JET_MovePrevious, grbitMove );
  453. if ( err == JET_errNoCurrentRecord )
  454. return JET_errRecordNotFound;
  455. else
  456. return JET_wrnSeekNotEqual;
  457. case JET_bitSeekLT:
  458. if ( err < 0 && err != JET_errRecordNotFound )
  459. return err;
  460. if ( err >= 0 || !fFoundLess )
  461. grbitMove |= JET_bitMoveKeyNE;
  462. err = ErrIsamMove( ppib, pfucb, JET_MovePrevious, grbitMove );
  463. if ( err == JET_errNoCurrentRecord )
  464. return JET_errRecordNotFound;
  465. else
  466. return err;
  467. }
  468. return err;
  469. }
  470. ERR VTAPI
  471. ErrIsamGotoBookmark( PIB *ppib, FUCB *pfucb, BYTE *pbBookmark, ULONG cbBookmark )
  472. {
  473. ERR err;
  474. LINE key;
  475. CheckPIB( ppib );
  476. CheckTable( ppib, pfucb );
  477. Assert( FFUCBIndex( pfucb ) );
  478. CheckNonClustered( pfucb );
  479. if ( cbBookmark != sizeof(SRID) )
  480. return JET_errInvalidBookmark;
  481. Assert( cbBookmark == sizeof(SRID) );
  482. /* reset copy buffer status
  483. /**/
  484. if ( FFUCBUpdatePrepared( pfucb ) )
  485. {
  486. CallR( ErrIsamPrepareUpdate( ppib, pfucb, JET_prepCancel ) );
  487. }
  488. /* reset index range limit
  489. /**/
  490. DIRResetIndexRange( pfucb );
  491. /* get node, and return error if this node is not there for caller.
  492. /**/
  493. DIRGotoBookmark( pfucb, *(SRID *)pbBookmark );
  494. Call( ErrDIRGet( pfucb ) );
  495. /* bookmark must be for node in table cursor is on
  496. /**/
  497. Assert( PgnoPMPgnoFDPOfPage( pfucb->ssib.pbf->ppage ) == pfucb->u.pfcb->pgnoFDP );
  498. /* goto bookmark record build key for secondary index
  499. /* to bookmark record
  500. /**/
  501. if ( pfucb->pfucbCurIndex != pfucbNil )
  502. {
  503. /* get non-clustered index cursor
  504. /**/
  505. FUCB *pfucbIdx = pfucb->pfucbCurIndex;
  506. /* allocate goto bookmark resources
  507. /**/
  508. if ( pfucb->pbKey == NULL )
  509. {
  510. pfucb->pbKey = LAlloc( 1L, JET_cbKeyMost );
  511. if ( pfucb->pbKey == NULL )
  512. return JET_errOutOfMemory;
  513. }
  514. /* make key for record for non-clustered index
  515. /**/
  516. key.pb = pfucb->pbKey;
  517. Call( ErrRECExtractKey( pfucb, (FDB *)pfucb->u.pfcb->pfdb, pfucbIdx->u.pfcb->pidb, &pfucb->lineData, &key, 1 ) );
  518. Assert( err != wrnFLDOutOfKeys );
  519. /* record must honor index no NULL segment requirements
  520. /**/
  521. Assert( !( pfucbIdx->u.pfcb->pidb->fidb & fidbNoNullSeg ) ||
  522. ( err != wrnFLDNullSeg && err != wrnFLDNullKey ) );
  523. /* if item is not index,
  524. /* then move before first instead of seeking
  525. /**/
  526. if ( ( err == wrnFLDNullKey && !( pfucbIdx->u.pfcb->pidb->fidb & fidbAllowAllNulls ) ) ||
  527. ( err == wrnFLDNullSeg && !( pfucbIdx->u.pfcb->pidb->fidb & fidbAllowSomeNulls ) ) )
  528. {
  529. /* This assumes that NULLs sort low.
  530. /**/
  531. DIRBeforeFirst( pfucbIdx );
  532. err = JET_errNoCurrentRecord;
  533. }
  534. else
  535. {
  536. /* move to DATA root
  537. /**/
  538. DIRGotoDataRoot( pfucbIdx );
  539. /* seek on secondary key
  540. /**/
  541. Call( ErrDIRDownKeyBookmark( pfucbIdx, &key, *(SRID *)pbBookmark ) );
  542. Assert( err == JET_errSuccess );
  543. /* item must be same as bookmark and
  544. /* clustered cursor must be on record.
  545. /**/
  546. Assert( pfucbIdx->lineData.pb != NULL );
  547. Assert( pfucbIdx->lineData.cb >= sizeof(SRID) );
  548. Assert( PcsrCurrent( pfucbIdx )->csrstat == csrstatOnCurNode );
  549. Assert( PcsrCurrent( pfucbIdx )->item == *(SRID *)pbBookmark );
  550. }
  551. }
  552. HandleError:
  553. KSReset( pfucb );
  554. return err;
  555. }
  556. ERR VTAPI
  557. ErrIsamGotoPosition( PIB *ppib, FUCB *pfucb, JET_RECPOS *precpos )
  558. {
  559. ERR err;
  560. FUCB *pfucb2ndIdx;
  561. SRID srid;
  562. CheckPIB( ppib );
  563. CheckTable( ppib, pfucb );
  564. CheckNonClustered( pfucb );
  565. /* Reset copy buffer status
  566. /**/
  567. if ( FFUCBUpdatePrepared( pfucb ) )
  568. {
  569. CallR( ErrIsamPrepareUpdate( ppib, pfucb, JET_prepCancel ) );
  570. }
  571. /* reset index range limit
  572. /**/
  573. DIRResetIndexRange( pfucb );
  574. /* reset key stat
  575. /**/
  576. KSReset( pfucb );
  577. /* set non clustered index pointer, may be null
  578. /**/
  579. pfucb2ndIdx = pfucb->pfucbCurIndex;
  580. if ( pfucb2ndIdx == pfucbNil )
  581. {
  582. /* move to DATA root
  583. /**/
  584. DIRGotoDataRoot( pfucb );
  585. err = ErrDIRGotoPosition( pfucb, precpos->centriesLT, precpos->centriesTotal );
  586. }
  587. else
  588. {
  589. /* move to DATA root
  590. /**/
  591. DIRGotoDataRoot( pfucb2ndIdx );
  592. err = ErrDIRGotoPosition( pfucb2ndIdx, precpos->centriesLT, precpos->centriesTotal );
  593. /* if the movement was successful and a non-clustered index is
  594. /* in use, then position clustered index to record.
  595. /**/
  596. if ( err == JET_errSuccess )
  597. {
  598. Assert( pfucb2ndIdx->lineData.pb != NULL );
  599. Assert( pfucb2ndIdx->lineData.cb >= sizeof(SRID) );
  600. srid = PcsrCurrent( pfucb2ndIdx )->item;
  601. DIRDeferGotoBookmark( pfucb, srid );
  602. Assert( PgnoOfSrid( srid ) != pgnoNull );
  603. }
  604. }
  605. /* if no records then return JET_errRecordNotFound
  606. /* otherwise return error from called routine
  607. /**/
  608. if ( err < 0 )
  609. {
  610. PcsrCurrent( pfucb )->csrstat = csrstatBeforeFirst;
  611. if ( pfucb2ndIdx != pfucbNil )
  612. {
  613. PcsrCurrent( pfucb2ndIdx )->csrstat = csrstatBeforeFirst;
  614. }
  615. }
  616. else
  617. {
  618. Assert (err==JET_errSuccess || err==wrnNDFoundLess || err==wrnNDFoundGreater );
  619. err = JET_errSuccess;
  620. }
  621. return err;
  622. }
  623. ERR VTAPI ErrIsamSetIndexRange( PIB *ppib, FUCB *pfucb, JET_GRBIT grbit )
  624. {
  625. ERR err;
  626. FUCB *pfucbIdx;
  627. /* ppib is not used in this function.
  628. /**/
  629. NotUsed( ppib );
  630. /* must be on index
  631. /**/
  632. if ( pfucb->u.pfcb->pidb == pidbNil && pfucb->pfucbCurIndex == pfucbNil )
  633. return JET_errNoCurrentIndex;
  634. /* key must be prepared
  635. /**/
  636. if ( ! ( FKSPrepared( pfucb ) ) )
  637. return JET_errKeyNotMade;
  638. /* get cursor for current index. If non-clustered index,
  639. /* then copy index range key to non-clustered index.
  640. /**/
  641. if ( pfucb->pfucbCurIndex != pfucbNil )
  642. {
  643. pfucbIdx = pfucb->pfucbCurIndex;
  644. if ( pfucbIdx->pbKey == NULL )
  645. {
  646. pfucbIdx->pbKey = LAlloc( 1L, JET_cbKeyMost );
  647. if ( pfucbIdx->pbKey == NULL )
  648. return JET_errOutOfMemory;
  649. }
  650. pfucbIdx->cbKey = pfucb->cbKey;
  651. memcpy( pfucbIdx->pbKey, pfucb->pbKey, pfucbIdx->cbKey );
  652. }
  653. else
  654. pfucbIdx = pfucb;
  655. /* set index range and check current position.
  656. /**/
  657. DIRSetIndexRange( pfucbIdx, grbit );
  658. err = ErrDIRCheckIndexRange( pfucbIdx );
  659. /* reset key status.
  660. /**/
  661. KSReset( pfucb );
  662. return err;
  663. }
  664.