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.

1102 lines
31 KiB

  1. #include "config.h"
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include "daedef.h"
  5. #include "util.h"
  6. #include "pib.h"
  7. #include "fmp.h"
  8. #include "page.h"
  9. #include "ssib.h"
  10. #include "fcb.h"
  11. #include "fucb.h"
  12. #include "stapi.h"
  13. #include "nver.h"
  14. #include "dirapi.h"
  15. #include "fdb.h"
  16. #include "idb.h"
  17. #include "spaceapi.h"
  18. #include "recapi.h"
  19. #include "recint.h"
  20. #include "logapi.h"
  21. DeclAssertFile; /* Declare file name for assert macros */
  22. /**************************** INTERNAL STUFF ***************************/
  23. typedef struct ATIPB { /*** AddToIndexParameterBlock ***/
  24. FUCB *pfucb;
  25. FUCB *pfucbIdx; // index's FUCB (can be pfucbNil)
  26. LINE lineNewData; // data to extract key from
  27. SRID srid; // srid of data record
  28. BOOL fFreeFUCB; // free index FUCB?
  29. } ATIPB;
  30. /* define semaphore to guard dbk counter
  31. /**/
  32. SgSemDefine( semDBK );
  33. typedef struct UIPB { /*** UpdateIndexParameterBlock ***/
  34. FUCB *pfucb;
  35. FUCB *pfucbIdx; // index's FUCB (can be pfucbNil)
  36. LINE lineOldData; // old data record
  37. SRID srid; // SRID of record
  38. LINE lineNewData; // new data record
  39. BOOL fOpenFUCB; // open index FUCB?
  40. BOOL fFreeFUCB; // free index FUCB?
  41. } UIPB;
  42. INLINE LOCAL ERR ErrRECInsert( PIB *ppib, FUCB *pfucb, SRID *psrid );
  43. INLINE LOCAL ERR ErrRECIAddToIndex( FCB *pfcbIdx, ATIPB *patipb );
  44. INLINE LOCAL ERR ErrRECReplace( PIB *ppib, FUCB *pfucb );
  45. INLINE LOCAL ERR ErrRECIUpdateIndex( FCB *pfcbIdx, UIPB *puipb );
  46. ERR VTAPI
  47. ErrIsamUpdate( PIB *ppib, FUCB *pfucb, BYTE *pb, ULONG cbMax, ULONG *pcbActual )
  48. {
  49. ERR err;
  50. SRID srid;
  51. CheckPIB( ppib );
  52. CheckTable( ppib, pfucb );
  53. CheckNonClustered( pfucb );
  54. if ( pcbActual != NULL )
  55. *pcbActual = sizeof(srid);
  56. if ( FFUCBReplacePrepared( pfucb ) )
  57. {
  58. if ( cbMax > 0 )
  59. {
  60. FUCBSetGetBookmark( pfucb );
  61. CallR( ErrDIRGetBookmark( pfucb, &srid ) );
  62. memcpy( pb, &srid, min( cbMax, sizeof(srid) ) );
  63. }
  64. err = ErrRECReplace( ppib, pfucb );
  65. }
  66. else if ( FFUCBInsertPrepared( pfucb ) )
  67. {
  68. err = ErrRECInsert( ppib, pfucb, &srid );
  69. if ( pb != NULL && cbMax > 0 && err >= 0 )
  70. {
  71. FUCBSetGetBookmark( pfucb );
  72. memcpy( pb, &srid, min( cbMax, sizeof(srid) ) );
  73. }
  74. }
  75. else
  76. err = JET_errUpdateNotPrepared;
  77. Assert( err != errDIRNotSynchronous );
  78. return err;
  79. }
  80. //+local
  81. // ErrRECInsert
  82. // ========================================================================
  83. // ErrRECInsert( PIB *ppib, FUCB *pfucb, OUTLINE *plineBookmark )
  84. //
  85. // Adds a record to a data file. All indexes on the data file are
  86. // updated to reflect the addition.
  87. //
  88. // PARAMETERS ppib PIB of user
  89. // pfucb FUCB for file
  90. // plineBookmark if this parameter is not NULL,
  91. // then bookmark of record is returned
  92. //
  93. // RETURNS Error code, one of the following:
  94. // JET_errSuccess Everything went OK.
  95. // -KeyDuplicate The record being added causes
  96. // an illegal duplicate entry in an index.
  97. // -NullKeyDisallowed A key of the new record is NULL.
  98. // -RecordNoCopy There is no working buffer to add from.
  99. // -NullInvalid The record being added contains
  100. // at least one null-valued field
  101. // which is defined as NotNull.
  102. // SIDE EFFECTS
  103. // After addition, file currency is left on the new record.
  104. // Index currency (if any) is left on the new index entry.
  105. // On failure, the currencies are returned to their initial states.
  106. //
  107. // COMMENTS
  108. // No currency is needed to add a record.
  109. // Index entries are not made for entirely-null keys.
  110. // A transaction is wrapped around this function. Thus, any
  111. // work done will be undone if a failure occurs.
  112. // Adding a record to a sequential file increments the
  113. // file's highest Database Key (DBK) and uses that DBK as
  114. // the key for the new record. However, if the PUT fails,
  115. // the max DBK is not reset to its former value. This can
  116. // create gaps in the DBK sequence.
  117. // This routine is also the interface for adding record to a
  118. // SORT process. The sort key is extracted and passed with
  119. // the data record to SORTAdd.
  120. // For temporary files, transaction logging is deactivated
  121. // for the duration of the routine.
  122. //-
  123. INLINE LOCAL ERR ErrRECInsert( PIB *ppib, FUCB *pfucb, SRID *psrid )
  124. {
  125. ERR err = JET_errSuccess; // error code of various utility
  126. KEY keyToAdd; // key of new data record
  127. BYTE rgbKeyBuf[ JET_cbKeyMost ]; // key buffer
  128. FCB *pfcbFile; // file's FCB
  129. FDB *pfdb; // field descriptor info
  130. FCB *pfcbIdx; // loop variable for each index on file
  131. ATIPB atipb; // parm block to ErrRECIAddToIndex
  132. FUCB *pfucbT;
  133. LINE *plineData;
  134. DBK dbk;
  135. LINE line;
  136. ULONG ulRecordAutoIncrement;
  137. ULONG ulTableAutoIncrement;
  138. BOOL fPrepareInsertIndex = fFalse;
  139. BOOL fCommit = fFalse;
  140. CheckPIB( ppib );
  141. CheckTable( ppib, pfucb );
  142. CheckNonClustered( pfucb );
  143. /* should have been checked in PrepareUpdate
  144. /**/
  145. Assert( FFUCBUpdatable( pfucb ) );
  146. Assert( FFUCBInsertPrepared( pfucb ) );
  147. /* assert reset rglineDiff delta logging
  148. /**/
  149. Assert( pfucb->clineDiff == 0 );
  150. Assert( pfucb->fCmprsLg == fFalse );
  151. /* efficiency variables
  152. /**/
  153. pfcbFile = pfucb->u.pfcb;
  154. Assert( pfcbFile != pfcbNil );
  155. pfdb = (FDB *)pfcbFile->pfdb;
  156. Assert( pfdb != pfdbNil );
  157. /* record to use for put
  158. /**/
  159. plineData = &pfucb->lineWorkBuf;
  160. Assert( !( FLineNull( plineData ) ) );
  161. if ( FRECIIllegalNulls( pfdb, plineData ) )
  162. return JET_errNullInvalid;
  163. /* if necessary, start a transaction in case anything fails
  164. /**/
  165. if ( ppib->level == 0 || !FPIBAggregateTransaction( ppib ) )
  166. {
  167. CallR( ErrDIRBeginTransaction( ppib ) );
  168. fCommit = fTrue;
  169. }
  170. /* open temp FUCB on data file
  171. /**/
  172. CallJ( ErrDIROpen( ppib, pfcbFile, 0, &pfucbT ), Abort );
  173. Assert(pfucbT != pfucbNil);
  174. FUCBSetIndex( pfucbT );
  175. /* abort if index is being built on file
  176. /**/
  177. if ( FFCBDenyDDL( pfcbFile, ppib ) )
  178. {
  179. err = JET_errWriteConflict;
  180. goto HandleError;
  181. }
  182. /* set version and autoinc fields
  183. /**/
  184. Assert( pfcbFile != pfcbNil );
  185. if ( pfdb->fidVersion != 0 && ! ( FFUCBColumnSet( pfucb, pfdb->fidVersion - fidFixedLeast ) ) )
  186. {
  187. LINE lineField;
  188. ULONG ul = 0;
  189. /* set field to zero
  190. /**/
  191. lineField.pb = (BYTE *)&ul;
  192. lineField.cb = sizeof(ul);
  193. Call( ErrRECIModifyField( pfucb, pfdb->fidVersion, 0, &lineField ) );
  194. }
  195. if ( pfdb->fidAutoInc != 0 )
  196. {
  197. Assert( FFUCBColumnSet( pfucb, pfdb->fidAutoInc - fidFixedLeast ) );
  198. // get the value of autoinc that the user sets to
  199. Call( ErrRECIRetrieve( pfucb, &pfdb->fidAutoInc, 0, &line, JET_bitRetrieveCopy ) );
  200. Assert( line.cb == sizeof(ulRecordAutoIncrement) );
  201. ulRecordAutoIncrement = *(UNALIGNED ULONG *)line.pb;
  202. /* move to FDP root and seek to autoincrement
  203. /**/
  204. DIRGotoFDPRoot( pfucbT );
  205. err = ErrDIRSeekPath( pfucbT, 1, pkeyAutoInc, fDIRPurgeParent );
  206. if ( err != JET_errSuccess )
  207. {
  208. if ( err > 0 )
  209. err = JET_errDatabaseCorrupted;
  210. goto HandleError;
  211. }
  212. Call( ErrDIRGet( pfucbT ) );
  213. Assert( pfucbT->lineData.cb == sizeof(ulTableAutoIncrement) );
  214. ulTableAutoIncrement = *(UNALIGNED ULONG *)pfucbT->lineData.pb;
  215. Assert( ulTableAutoIncrement != 0 );
  216. /* update FDP autoinc to be one greater than set value.
  217. /**/
  218. if ( ulRecordAutoIncrement >= ulTableAutoIncrement)
  219. {
  220. ulTableAutoIncrement = ulRecordAutoIncrement + 1;
  221. line.pb = (BYTE *)&ulTableAutoIncrement;
  222. line.cb = sizeof(ulTableAutoIncrement);
  223. Call( ErrDIRReplace( pfucbT, &line, fDIRNoVersion ) );
  224. }
  225. }
  226. /* get key to add with new record
  227. /**/
  228. keyToAdd.pb = rgbKeyBuf;
  229. if ( pfcbFile->pidb == pidbNil )
  230. {
  231. /* file is sequential
  232. /**/
  233. SgSemRequest( semDBK );
  234. dbk = ++pfcbFile->dbkMost;
  235. SgSemRelease( semDBK );
  236. keyToAdd.cb = sizeof(DBK);
  237. keyToAdd.pb[0] = (BYTE)((dbk >> 24) & 0xff);
  238. keyToAdd.pb[1] = (BYTE)((dbk >> 16) & 0xff);
  239. keyToAdd.pb[2] = (BYTE)((dbk >> 8) & 0xff);
  240. keyToAdd.pb[3] = (BYTE)(dbk & 0xff);
  241. }
  242. else
  243. {
  244. /* file is clustered
  245. /**/
  246. Call( ErrRECExtractKey( pfucbT, pfdb, pfcbFile->pidb, plineData, &keyToAdd, 1 ) );
  247. Assert( err == wrnFLDNullKey ||
  248. err == wrnFLDNullSeg ||
  249. err == JET_errSuccess );
  250. if ( ( pfcbFile->pidb->fidb & fidbNoNullSeg ) && ( err == wrnFLDNullKey || err == wrnFLDNullSeg ) )
  251. Error( JET_errNullKeyDisallowed, HandleError )
  252. }
  253. /* insert record. Move to DATA root.
  254. /**/
  255. DIRGotoDataRoot( pfucbT );
  256. if ( pfcbFile->pidb == pidbNil )
  257. {
  258. /* file is sequential
  259. /**/
  260. Call( ErrDIRInsert( pfucbT, plineData, &keyToAdd,
  261. fDIRVersion | fDIRPurgeParent ) );
  262. }
  263. else
  264. {
  265. Call( ErrDIRInsert( pfucbT, plineData, &keyToAdd,
  266. fDIRVersion | fDIRPurgeParent |
  267. ( pfcbFile->pidb->fidb&fidbUnique ? 0 : fDIRDuplicate ) ) );
  268. }
  269. /* return bookmark of inserted record
  270. /**/
  271. DIRGetBookmark( pfucbT, psrid );
  272. /* insert item in non-clustered indexes
  273. /**/
  274. for ( pfcbIdx = pfcbFile->pfcbNextIndex;
  275. pfcbIdx != pfcbNil;
  276. pfcbIdx = pfcbIdx->pfcbNextIndex )
  277. {
  278. if ( !fPrepareInsertIndex )
  279. {
  280. /* get SRID of inserted record
  281. /**/
  282. DIRGetBookmark( pfucbT, &atipb.srid );
  283. /* set atipb for index insertion.
  284. /**/
  285. atipb.pfucb = pfucbT;
  286. atipb.lineNewData = *plineData;
  287. // atipb.pfucbIdx = pfucbNil;
  288. atipb.fFreeFUCB = fFalse;
  289. fPrepareInsertIndex = fTrue;
  290. }
  291. atipb.fFreeFUCB = pfcbIdx->pfcbNextIndex == pfcbNil;
  292. Call( ErrRECIAddToIndex( pfcbIdx, &atipb ) );
  293. }
  294. /* commit transaction
  295. /**/
  296. if ( fCommit )
  297. {
  298. Call( ErrDIRCommitTransaction( ppib ) );
  299. }
  300. FUCBResetUpdateSeparateLV( pfucb );
  301. FUCBResetCbstat( pfucb );
  302. /* discard temp FUCB
  303. /**/
  304. DIRClose( pfucbT );
  305. return err;
  306. HandleError:
  307. Assert( err < 0 );
  308. DIRClose( pfucbT );
  309. Abort:
  310. if ( fCommit )
  311. CallS( ErrDIRRollback( ppib ) );
  312. return err;
  313. }
  314. //+local
  315. // ErrRECIAddToIndex
  316. // ========================================================================
  317. // ERR ErrRECIAddToIndex( FCB *pfcbIdx, ATIPB patipb )
  318. //
  319. // Extracts key from data record, opens the index, adds that key with
  320. // the given SRID to the index, and closes the index.
  321. //
  322. // PARAMETERS pfcbIdx FCB of index to insert into
  323. // patipb->ppib who is calling this routine
  324. // patipb->pfucbIdx pointer to index's FUCB. If pfucbNil,
  325. // an FUCB will be allocated by DIROpen.
  326. // patipb->lineNewData.cb length of data record
  327. // patipb->lineNewData.pb data to extract key from
  328. // patipb->srid SRID of data record
  329. // patipb->fFreeFUCB free index FUCB?
  330. //
  331. // RETURNS JET_errSuccess, or error code from failing routine
  332. //
  333. // SIDE EFFECTS if patipb->pfucbIdx==pfucbNil, ErrDIROpen will allocate
  334. // an FUCB and it will be pointed at it.
  335. // If fFreeFUCB is fFalse, patipb->pfucbIdx should
  336. // be used in a subsequent ErrDIROpen.
  337. // SEE ALSO Insert
  338. //-
  339. INLINE LOCAL ERR ErrRECIAddToIndex( FCB *pfcbIdx, ATIPB *patipb )
  340. {
  341. ERR err = JET_errSuccess; // error code of various utility
  342. CSR **ppcsrIdx; // index's currency
  343. KEY keyToAdd; // key to add to secondary index
  344. BYTE rgbKeyBuf[ JET_cbKeyMost ]; // key extracted from data
  345. LINE lineSRID; // SRID to add to index
  346. ULONG itagSequence; // used to extract keys
  347. ULONG ulAddFlags; // flags to DIRAdd
  348. BOOL fNullKey = fFalse; // extracted NullTaggedKey -- so no more keys to extract
  349. Assert( pfcbIdx != pfcbNil );
  350. Assert( pfcbIdx->pfdb != pfdbNil );
  351. Assert( pfcbIdx->pidb != pidbNil );
  352. Assert( patipb != NULL );
  353. Assert( !FLineNull( &patipb->lineNewData ) );
  354. Assert( patipb->pfucb != pfucbNil );
  355. Assert( patipb->pfucb->ppib != ppibNil );
  356. Assert( patipb->pfucb->ppib->level < levelMax );
  357. /* open FUCB on this index
  358. /**/
  359. CallR( ErrDIROpen( patipb->pfucb->ppib, pfcbIdx, 0, &patipb->pfucbIdx ) )
  360. Assert( patipb->pfucbIdx != pfucbNil );
  361. /* cursor on non-clustering index
  362. /**/
  363. FUCBSetIndex( patipb->pfucbIdx );
  364. FUCBSetNonClustered( patipb->pfucbIdx );
  365. ppcsrIdx = &PcsrCurrent( patipb->pfucbIdx );
  366. Assert( *ppcsrIdx != pcsrNil );
  367. lineSRID.cb = sizeof(SRID);
  368. lineSRID.pb = (BYTE *) &patipb->srid;
  369. ulAddFlags = ( pfcbIdx->pidb->fidb&fidbUnique ?
  370. 0 : fDIRDuplicate ) | fDIRPurgeParent;
  371. /* add all keys for this index from new data record
  372. /**/
  373. keyToAdd.pb = rgbKeyBuf;
  374. for ( itagSequence = 1; ; itagSequence++ )
  375. {
  376. Call( ErrDIRGet( patipb->pfucb ) );
  377. patipb->lineNewData = patipb->pfucb->lineData;
  378. Call( ErrRECExtractKey( patipb->pfucb, (FDB *)pfcbIdx->pfdb, pfcbIdx->pidb, &patipb->lineNewData, &keyToAdd, itagSequence ) );
  379. Assert( err == wrnFLDNullKey ||
  380. err == wrnFLDOutOfKeys ||
  381. err == wrnFLDNullSeg ||
  382. err == JET_errSuccess );
  383. if ( err == wrnFLDOutOfKeys )
  384. {
  385. Assert( itagSequence > 1 );
  386. break;
  387. }
  388. if ( ( pfcbIdx->pidb->fidb & fidbNoNullSeg ) && ( err == wrnFLDNullKey || err == wrnFLDNullSeg ) )
  389. {
  390. err = JET_errNullKeyDisallowed;
  391. goto HandleError;
  392. }
  393. if ( err == wrnFLDNullKey )
  394. {
  395. if ( pfcbIdx->pidb->fidb & fidbAllowAllNulls )
  396. {
  397. ulAddFlags |= fDIRDuplicate;
  398. fNullKey = fTrue;
  399. }
  400. else
  401. break;
  402. }
  403. else
  404. {
  405. if ( err == wrnFLDNullSeg && !( pfcbIdx->pidb->fidb & fidbAllowSomeNulls ) )
  406. break;
  407. }
  408. /* move to DATA root and insert index node
  409. /**/
  410. DIRGotoDataRoot( patipb->pfucbIdx );
  411. Call( ErrDIRInsert( patipb->pfucbIdx, &lineSRID, &keyToAdd, fDIRVersion | ulAddFlags ) )
  412. /* dont keep extracting for keys with no tagged segments
  413. /**/
  414. if ( !( pfcbIdx->pidb->fidb & fidbHasMultivalue ) || fNullKey )
  415. break;
  416. }
  417. /* supress warnings
  418. /**/
  419. Assert( err == wrnFLDNullKey ||
  420. err == wrnFLDOutOfKeys ||
  421. err == wrnFLDNullSeg ||
  422. err == JET_errSuccess );
  423. err = JET_errSuccess;
  424. HandleError:
  425. /* close the FUCB
  426. /**/
  427. DIRClose( patipb->pfucbIdx );
  428. patipb->pfucbIdx = pfucbNil;
  429. Assert( err < 0 || err == JET_errSuccess );
  430. return err;
  431. }
  432. //+local
  433. // ErrRECReplace
  434. // ========================================================================
  435. // ErrRECReplace( PIB *ppib, FUCB *pfucb )
  436. //
  437. // Updates a record in a data file. All indexes on the data file are
  438. // updated to reflect the updated data record.
  439. //
  440. // PARAMETERS ppib PIB of this user
  441. // pfucb FUCB for file
  442. // RETURNS Error code, one of the following:
  443. // JET_errSuccess Everything went OK.
  444. // -NoCurrentRecord There is no current record
  445. // to update.
  446. // -RecordNoCopy There is no working buffer
  447. // to update from.
  448. // -KeyDuplicate The new record data causes an
  449. // illegal duplicate index entry
  450. // to be generated.
  451. // -RecordClusteredChanged The new data causes the clustered
  452. // key to change.
  453. // SIDE EFFECTS
  454. // After update, file currency is left on the updated record.
  455. // Similar for index currency.
  456. // The effect of a GetNext or GetPrevious operation will be
  457. // the same in either case. On failure, the currencies are
  458. // returned to their initial states.
  459. // If there is a working buffer for SetField commands,
  460. // it is discarded.
  461. //
  462. // COMMENTS
  463. // If currency is not ON a record, the update will fail.
  464. // A transaction is wrapped around this function. Thus, any
  465. // work done will be undone if a failure occurs.
  466. // For temporary files, transaction logging is deactivated
  467. // for the duration of the routine.
  468. // Index entries are not made for entirely-null keys.
  469. //-
  470. INLINE LOCAL ERR ErrRECReplace( PIB *ppib, FUCB *pfucb )
  471. {
  472. ERR err = JET_errSuccess; // error code of various utility
  473. FCB *pfcbFile; // file's FCB
  474. FCB *pfcbIdx; // loop variable for each index on file
  475. FCB *pfcbCurIdx; // FCB of current index (if any)
  476. IDB *pidbFile; // IDB of table (if any)
  477. UIPB uipb; // parameter block to ErrRECIUpdateIndex
  478. BOOL fTaggedChanged; // SetField done on any tagged field?
  479. BF *pbf = pbfNil;
  480. LINE *plineNewData;
  481. FID fidFixedLast;
  482. FID fidVarLast;
  483. FID fid;
  484. BOOL fUpdateIndex;
  485. BOOL fCommit = fFalse;
  486. INT fFlags;
  487. CheckPIB( ppib );
  488. CheckTable( ppib, pfucb );
  489. CheckNonClustered( pfucb );
  490. /* should have been checked in PrepareUpdate
  491. /**/
  492. Assert( FFUCBUpdatable( pfucb ) );
  493. Assert( FFUCBReplacePrepared( pfucb ) );
  494. /* efficiency variables
  495. /**/
  496. fTaggedChanged = FFUCBTaggedSet( pfucb );
  497. pfcbFile = pfucb->u.pfcb;
  498. Assert( pfcbFile != pfcbNil );
  499. fidFixedLast = pfcbFile->pfdb->fidFixedLast;
  500. fidVarLast = pfcbFile->pfdb->fidVarLast;
  501. /* must initialize pfucb for error handling.
  502. /**/
  503. uipb.pfucbIdx = pfucbNil;
  504. /* record to use for update
  505. /**/
  506. plineNewData = &pfucb->lineWorkBuf;
  507. Assert( !( FLineNull( plineNewData ) ) );
  508. /* start a transaction in case anything fails
  509. /**/
  510. if ( ppib->level == 0 || !FPIBAggregateTransaction( ppib ) )
  511. {
  512. CallR( ErrDIRBeginTransaction( ppib ) );
  513. fCommit = fTrue;
  514. }
  515. /* optimistic locking -- ensure that record has not changed since PrepareUpdate
  516. /**/
  517. if ( FFUCBReplaceNoLockPrepared( pfucb ) )
  518. {
  519. Call( ErrDIRGet( pfucb ) );
  520. if ( !FChecksum( pfucb ) )
  521. Call( JET_errWriteConflict );
  522. }
  523. /* abort if index is being built on file
  524. /**/
  525. if ( FFCBDenyDDL( pfcbFile, ppib ) )
  526. {
  527. Call( JET_errWriteConflict );
  528. }
  529. /* if need to update indexes, then cache old record.
  530. /**/
  531. fUpdateIndex = ( pfcbFile->fAllIndexTagged && fTaggedChanged ) ||
  532. FIndexedFixVarChanged( pfcbFile->rgbitAllIndex,
  533. pfucb->rgbitSet, fidFixedLast, fidVarLast );
  534. if ( fUpdateIndex )
  535. {
  536. /* get a temp buffer to hold old data.
  537. /**/
  538. Call( ErrBFAllocTempBuffer( &pbf ) );
  539. Assert( pbf->ppage != 0 );
  540. uipb.lineOldData.pb = (BYTE*)pbf->ppage;
  541. /* refresh currency.
  542. /**/
  543. Call( ErrDIRGet( pfucb ) );
  544. /* copy old data for index update.
  545. /**/
  546. LineCopy( &uipb.lineOldData, &pfucb->lineData );
  547. /* make sure clustered key did not change.
  548. /**/
  549. pidbFile = pfcbFile->pidb;
  550. if ( pidbFile != pidbNil )
  551. {
  552. /*
  553. * Quick check for unchanged key: if no fixed or var index segment
  554. * has changed, and either (1) there are no tagged index segments,
  555. * or (2) there is a tagged segment, but no tagged field (indexed
  556. * or not) has changed, then the key has not changed.
  557. */
  558. if ( ( ( pidbFile->fidb & fidbHasTagged ) && fTaggedChanged ) ||
  559. FIndexedFixVarChanged( pidbFile->rgbitIdx, pfucb->rgbitSet, fidFixedLast, fidVarLast ) )
  560. {
  561. KEY keyOld;
  562. KEY keyNew;
  563. BYTE rgbOldKeyBuf[ JET_cbKeyMost ];
  564. BYTE rgbNewKeyBuf[ JET_cbKeyMost ];
  565. Assert( fUpdateIndex );
  566. /* get new key from copy buffer
  567. /**/
  568. keyNew.pb = rgbNewKeyBuf;
  569. Call( ErrRECExtractKey( pfucb, (FDB *)pfcbFile->pfdb, pidbFile, plineNewData, &keyNew, 1 ) );
  570. Assert( err == wrnFLDNullKey ||
  571. err == wrnFLDNullSeg ||
  572. err == JET_errSuccess );
  573. /* get the old key from the node
  574. /**/
  575. keyOld.pb = rgbOldKeyBuf;
  576. Call( ErrRECExtractKey( pfucb, (FDB *)pfcbFile->pfdb, pidbFile, &uipb.lineOldData, &keyOld, 1 ) );
  577. Assert( err == wrnFLDNullKey ||
  578. err == wrnFLDNullSeg ||
  579. err == JET_errSuccess );
  580. /* record must honor index no NULL segment requirements
  581. /**/
  582. Assert( !( pidbFile->fidb & fidbNoNullSeg ) ||
  583. ( err != wrnFLDNullSeg && err != wrnFLDNullKey ) );
  584. if ( keyOld.cb != keyNew.cb || memcmp( keyOld.pb, keyNew.pb, keyOld.cb ) != 0 )
  585. {
  586. Error( JET_errRecordClusteredChanged, HandleError )
  587. }
  588. }
  589. }
  590. }
  591. /* set autoinc and version fields if they are present
  592. /**/
  593. Assert( FFUCBIndex( pfucb ) );
  594. fid = pfcbFile->pfdb->fidVersion;
  595. if ( fid != 0 )
  596. {
  597. LINE lineField;
  598. ULONG ul;
  599. /* increment field from value in current record
  600. /**/
  601. Call( ErrRECIRetrieve( pfucb, &fid, 0, &lineField, 0 ) );
  602. /* handle case where field is NULL when column added
  603. /* to table with records present
  604. /**/
  605. if ( lineField.cb == 0 )
  606. {
  607. ul = 1;
  608. lineField.cb = sizeof(ul);
  609. lineField.pb = (BYTE *)&ul;
  610. }
  611. else
  612. {
  613. Assert( lineField.cb == sizeof(ULONG) );
  614. ++*(UNALIGNED ULONG *)lineField.pb;
  615. }
  616. Call( ErrRECIModifyField( pfucb, fid, 0, &lineField ) );
  617. }
  618. /* replace data.
  619. /* Do not version if before image already exists and record size
  620. /* has not changed.
  621. /**/
  622. // UNDONE: reenable optimization on not versioning when already
  623. // versioned for pessomistic locking but with indication
  624. // to loggging recovery for rollback.
  625. // if ( FFUCBReplaceNoLockPrepared( pfucb ) )
  626. // {
  627. fFlags = fDIRVersion;
  628. // }
  629. // else
  630. // {
  631. // Assert( pfucb->cbRecord > 0 );
  632. // if ( pfucb->cbRecord != plineNewData->cb )
  633. // fFlags = fDIRVersion;
  634. // else
  635. // fFlags = 0;
  636. // }
  637. /* if updated separate long values then delete
  638. /* removed long values.
  639. /**/
  640. if ( FFUCBUpdateSeparateLV( pfucb ) )
  641. {
  642. Call( ErrRECAffectLongFields( pfucb, NULL, fDereferenceRemoved ) );
  643. }
  644. Call( ErrDIRReplace( pfucb, plineNewData, fFlags ) );
  645. /* update indexes
  646. /**/
  647. if ( fUpdateIndex )
  648. {
  649. uipb.pfucb = pfucb;
  650. uipb.lineNewData = *plineNewData;
  651. uipb.fOpenFUCB = fTrue;
  652. uipb.fFreeFUCB = fFalse;
  653. /* get SRID of record
  654. /**/
  655. DIRGetBookmark( pfucb, &uipb.srid );
  656. pfcbCurIdx = pfucb->pfucbCurIndex != pfucbNil ? pfucb->pfucbCurIndex->u.pfcb : pfcbNil;
  657. for ( pfcbIdx = pfcbFile->pfcbNextIndex;
  658. pfcbIdx != pfcbNil;
  659. pfcbIdx = pfcbIdx->pfcbNextIndex )
  660. {
  661. if ( ( pfcbIdx->pidb->fidb & fidbHasTagged && fTaggedChanged ) ||
  662. FIndexedFixVarChanged( pfcbIdx->pidb->rgbitIdx,
  663. pfucb->rgbitSet,
  664. fidFixedLast,
  665. fidVarLast ) )
  666. {
  667. Call( ErrRECIUpdateIndex( pfcbIdx, &uipb ) );
  668. }
  669. }
  670. }
  671. /* commit transaction
  672. /**/
  673. if ( fCommit )
  674. {
  675. Call( ErrDIRCommitTransaction( ppib ) );
  676. }
  677. FUCBResetUpdateSeparateLV( pfucb );
  678. FUCBResetCbstat( pfucb );
  679. /* reset rglineDiff delta logging
  680. /**/
  681. pfucb->clineDiff = 0;
  682. pfucb->fCmprsLg = fFalse;
  683. HandleError:
  684. if ( uipb.pfucbIdx != pfucbNil )
  685. DIRClose( uipb.pfucbIdx );
  686. if ( pbf != pbfNil )
  687. BFSFree( pbf );
  688. /* rollback if necessary
  689. /**/
  690. if ( err < 0 && fCommit )
  691. {
  692. CallS( ErrDIRRollback( ppib ) );
  693. }
  694. return err;
  695. }
  696. BOOL FIndexedFixVarChanged( BYTE *rgbitIdx, BYTE *rgbitSet, FID fidFixedLast, FID fidVarLast )
  697. {
  698. LONG *plIdx;
  699. LONG *plIdxMax;
  700. LONG *plSet;
  701. /* check fixed fields (only those defined)
  702. /**/
  703. plIdx = (LONG *)rgbitIdx;
  704. plSet = (LONG *)rgbitSet;
  705. plIdxMax = plIdx + ( fidFixedLast + 31 ) / 32;
  706. while ( plIdx < plIdxMax && !( *plIdx & *plSet ) )
  707. plIdx++, plSet++;
  708. /* indexed fixed field changed
  709. /**/
  710. if ( plIdx < plIdxMax )
  711. return fTrue;
  712. /* check variable fields (only those defined)
  713. /**/
  714. plIdx = (LONG *)rgbitIdx + 4;
  715. plSet = (LONG *)rgbitSet + 4;
  716. plIdxMax = plIdx + ( fidVarLast - ( fidVarLeast - 1 ) + 31 ) / 32;
  717. while ( plIdx < plIdxMax && !( *plIdx & *plSet ) )
  718. plIdx++, plSet++;
  719. return ( plIdx < plIdxMax );
  720. }
  721. //+local
  722. // ErrRECIUpdateIndex
  723. // ========================================================================
  724. // ERR ErrRECIUpdateIndex(pfcbIdx, puipb)
  725. // FCB *pfcbIdx; // IN FCB of index to insert into
  726. // UIPB *puipb; // INOUT parameter block
  727. // Extracts keys from old and new data records, and if they are different,
  728. // opens the index, adds the new index entry, deletes the old index entry,
  729. // and closes the index.
  730. //
  731. // PARAMETERS
  732. // pfcbIdx FCB of index to insert into
  733. // puipb->ppib who is calling this routine
  734. // puipb->pfucbIdx pointer to index's FUCB. If pfucbNil,
  735. // an FUCB will be allocated by DIROpen.
  736. // puipb->lineOldData.cb length of old data record
  737. // puipb->lineOldData.pb old data to extract old key from
  738. // puipb->srid SRID of record
  739. // puipb->lineNewData.cb length of new data record
  740. // puipb->lineNewData.pb new data to extract new key from
  741. // puipb->fFreeFUCB free index FUCB?
  742. // RETURNS JET_errSuccess, or error code from failing routine
  743. // SIDE EFFECTS if patipb->pfucbIdx==pfucbNil, ErrDIROpen will allocate
  744. // an FUCB and it will be pointed at it.
  745. // If fFreeFUCB is fFalse, patipb->pfucbIdx should
  746. // be used in a subsequent ErrDIROpen.
  747. // SEE ALSO Replace
  748. //-
  749. INLINE LOCAL ERR ErrRECIUpdateIndex( FCB *pfcbIdx, UIPB *puipb )
  750. {
  751. ERR err = JET_errSuccess; // error code of various utility
  752. LINE lineSRID; // SRID to add to index
  753. KEY keyOld; // key extracted from old record
  754. BYTE rgbOldKeyBuf[ JET_cbKeyMost]; // buffer for old key
  755. KEY keyNew; // key extracted from new record
  756. BYTE rgbNewKeyBuf[ JET_cbKeyMost ]; // buffer for new key
  757. ULONG itagSequenceOld; // used to extract keys
  758. ULONG itagSequenceNew; // used to extract keys
  759. BOOL fHasMultivalue; // index has tagged segment?
  760. BOOL fMustDelete; // record no longer generates key?
  761. BOOL fMustAdd; // record now generates this key?
  762. BOOL fAllowNulls; // this index allows NULL keys?
  763. BOOL fAllowSomeNulls; // this index allows keys with NULL segment(s)?
  764. BOOL fNoNullSeg; // this index prohibits any NULL key segment?
  765. BOOL fDoOldNullKey;
  766. BOOL fDoNewNullKey;
  767. Assert( pfcbIdx != pfcbNil );
  768. Assert( pfcbIdx->pfdb != pfdbNil );
  769. Assert( pfcbIdx->pidb != pidbNil );
  770. Assert( puipb != NULL );
  771. Assert( puipb->pfucb != pfucbNil );
  772. Assert( puipb->pfucb->ppib != ppibNil );
  773. Assert( puipb->pfucb->ppib->level < levelMax );
  774. Assert( !FLineNull( &puipb->lineOldData ) );
  775. Assert( !FLineNull( &puipb->lineNewData ) );
  776. /*** open FUCB on this index ***/
  777. CallR( ErrDIROpen( puipb->pfucb->ppib, pfcbIdx, 0, &puipb->pfucbIdx ) );
  778. Assert( puipb->pfucbIdx != pfucbNil );
  779. FUCBSetIndex( puipb->pfucbIdx );
  780. FUCBSetNonClustered( puipb->pfucbIdx );
  781. fHasMultivalue = pfcbIdx->pidb->fidb & fidbHasMultivalue;
  782. fAllowNulls = pfcbIdx->pidb->fidb & fidbAllowAllNulls;
  783. fAllowSomeNulls = pfcbIdx->pidb->fidb & fidbAllowSomeNulls;
  784. fNoNullSeg = pfcbIdx->pidb->fidb & fidbNoNullSeg;
  785. #if DBFORMATCHANGE
  786. Assert( ( fAllowNulls || fAllowSomeNulls ) ^ fNoNullSeg );
  787. // if fAllowNulls, then fAllowSomeNulls needs to be true
  788. Assert( !fAllowNulls || fAllowSomeNulls );
  789. #endif
  790. keyOld.pb = rgbOldKeyBuf;
  791. keyNew.pb = rgbNewKeyBuf;
  792. /* delete the old key from the index
  793. /**/
  794. fDoOldNullKey = fFalse;
  795. for ( itagSequenceOld = 1; ; itagSequenceOld++ )
  796. {
  797. Call( ErrRECExtractKey( puipb->pfucb, (FDB *)pfcbIdx->pfdb, pfcbIdx->pidb, &puipb->lineOldData, &keyOld, itagSequenceOld ) );
  798. Assert( err == wrnFLDNullKey ||
  799. err == wrnFLDOutOfKeys ||
  800. err == wrnFLDNullSeg ||
  801. err == JET_errSuccess );
  802. if ( err == wrnFLDOutOfKeys )
  803. {
  804. Assert( itagSequenceOld > 1 );
  805. break;
  806. }
  807. /* record must honor index no NULL segment requirements
  808. /**/
  809. Assert( !fNoNullSeg || ( err != wrnFLDNullSeg && err != wrnFLDNullKey ) );
  810. if ( err == wrnFLDNullKey )
  811. {
  812. if ( fAllowNulls )
  813. fDoOldNullKey = fTrue;
  814. else
  815. break;
  816. }
  817. else
  818. {
  819. if ( err == wrnFLDNullSeg && !fAllowSomeNulls )
  820. break;
  821. }
  822. fMustDelete = fTrue;
  823. fDoNewNullKey = fFalse;
  824. for ( itagSequenceNew = 1; ; itagSequenceNew++ )
  825. {
  826. /* extract key from new data in copy buffer
  827. /**/
  828. Call( ErrRECExtractKey( puipb->pfucb, (FDB *)pfcbIdx->pfdb, pfcbIdx->pidb, &puipb->lineNewData, &keyNew, itagSequenceNew ) );
  829. Assert( err == wrnFLDNullKey ||
  830. err == wrnFLDOutOfKeys ||
  831. err == wrnFLDNullSeg ||
  832. err == JET_errSuccess );
  833. if ( err == wrnFLDOutOfKeys )
  834. {
  835. Assert( itagSequenceNew > 1 );
  836. break;
  837. }
  838. if ( err == wrnFLDNullKey )
  839. {
  840. if ( fAllowNulls )
  841. fDoNewNullKey = fTrue;
  842. else
  843. break;
  844. }
  845. else
  846. {
  847. if ( err == wrnFLDNullSeg && !fAllowSomeNulls )
  848. break;
  849. }
  850. if ( keyOld.cb == keyNew.cb && memcmp( keyOld.pb, keyNew.pb, keyOld.cb ) == 0 )
  851. {
  852. fMustDelete = fFalse;
  853. break;
  854. }
  855. if ( !fHasMultivalue || fDoNewNullKey )
  856. break;
  857. }
  858. if ( fMustDelete )
  859. {
  860. /* move to DATA root. Seek to index entry.
  861. /**/
  862. DIRGotoDataRoot( puipb->pfucbIdx );
  863. Call( ErrDIRDownKeyBookmark( puipb->pfucbIdx, &keyOld, puipb->srid ) );
  864. Call( ErrDIRDelete( puipb->pfucbIdx, fDIRVersion ) );
  865. }
  866. if ( !fHasMultivalue || fDoOldNullKey )
  867. break;
  868. }
  869. /* insert the new key into the index
  870. /**/
  871. lineSRID.cb = sizeof(SRID);
  872. lineSRID.pb = (BYTE *)&puipb->srid;
  873. fDoNewNullKey = fFalse;
  874. for ( itagSequenceNew = 1; ; itagSequenceNew++ )
  875. {
  876. /* extract key from new data in copy buffer
  877. /**/
  878. Call( ErrRECExtractKey( puipb->pfucb, (FDB *)pfcbIdx->pfdb, pfcbIdx->pidb,
  879. &puipb->lineNewData, &keyNew, itagSequenceNew ) );
  880. Assert( err == wrnFLDNullKey ||
  881. err == wrnFLDOutOfKeys ||
  882. err == wrnFLDNullSeg ||
  883. err == JET_errSuccess );
  884. if ( err == wrnFLDOutOfKeys )
  885. {
  886. Assert( itagSequenceNew > 1 );
  887. break;
  888. }
  889. if ( fNoNullSeg && ( err == wrnFLDNullSeg || err == wrnFLDNullKey ) )
  890. {
  891. err = JET_errNullKeyDisallowed;
  892. goto HandleError;
  893. }
  894. if ( err == wrnFLDNullKey )
  895. {
  896. if ( fAllowNulls )
  897. fDoNewNullKey = fTrue;
  898. else
  899. break;
  900. }
  901. else
  902. {
  903. if ( err == wrnFLDNullSeg && !fAllowSomeNulls )
  904. break;
  905. }
  906. fMustAdd = fTrue;
  907. fDoOldNullKey = fFalse;
  908. for ( itagSequenceOld = 1; ; itagSequenceOld++ )
  909. {
  910. Call( ErrRECExtractKey( puipb->pfucb, (FDB *)pfcbIdx->pfdb, pfcbIdx->pidb,
  911. &puipb->lineOldData, &keyOld, itagSequenceOld ) );
  912. Assert( err == wrnFLDNullKey ||
  913. err == wrnFLDOutOfKeys ||
  914. err == wrnFLDNullSeg ||
  915. err == JET_errSuccess );
  916. if ( err == wrnFLDOutOfKeys )
  917. {
  918. Assert( itagSequenceOld > 1 );
  919. break;
  920. }
  921. /* record must honor index no NULL segment requirements
  922. /**/
  923. Assert( !( pfcbIdx->pidb->fidb & fidbNoNullSeg ) ||
  924. ( err != wrnFLDNullSeg && err != wrnFLDNullKey ) );
  925. if ( err == wrnFLDNullKey )
  926. {
  927. if ( fAllowNulls )
  928. fDoOldNullKey = fTrue;
  929. else
  930. break;
  931. }
  932. else
  933. {
  934. if ( err == wrnFLDNullSeg && !fAllowSomeNulls )
  935. break;
  936. }
  937. if ( keyOld.cb == keyNew.cb &&
  938. memcmp( keyOld.pb, keyNew.pb, keyOld.cb ) ==0 )
  939. {
  940. fMustAdd = fFalse;
  941. break;
  942. }
  943. if ( !fHasMultivalue || fDoOldNullKey )
  944. break;
  945. }
  946. if ( fMustAdd )
  947. {
  948. BOOL fAllowDupls = fDoNewNullKey || !(pfcbIdx->pidb->fidb & fidbUnique);
  949. /* move to DATA root and insert new index entry.
  950. /**/
  951. DIRGotoDataRoot( puipb->pfucbIdx );
  952. Call( ErrDIRInsert(puipb->pfucbIdx, &lineSRID, &keyNew,
  953. (fAllowDupls ? fDIRDuplicate : 0) |
  954. fDIRPurgeParent | fDIRVersion ) );
  955. }
  956. if ( !fHasMultivalue || fDoNewNullKey )
  957. break;
  958. }
  959. /* supress warnings
  960. /**/
  961. Assert( err == wrnFLDNullKey ||
  962. err == wrnFLDOutOfKeys ||
  963. err == wrnFLDNullSeg ||
  964. err == JET_errSuccess );
  965. err = JET_errSuccess;
  966. HandleError:
  967. /* close the FUCB.
  968. /**/
  969. DIRClose( puipb->pfucbIdx );
  970. puipb->pfucbIdx = pfucbNil;
  971. Assert( err < 0 || err == JET_errSuccess );
  972. return err;
  973. }