home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / code / kdbf / example / rest.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  18.6 KB  |  630 lines

  1. /****************************************************************************
  2. *                                                                           
  3. * FILE: REST.CPP
  4. *
  5. * DESCRIPTION:  This file contains the member functions for the class
  6. *               MainRestaurant used in the sample program for the   
  7. *               C++ Database Framework.
  8. *               
  9. *
  10. ****************************************************************************/
  11. #include <string.h>
  12. #include "demo.h"
  13.  
  14. //
  15. // Field arrays for the composite keys used in searches of the main table.
  16. //
  17. FIELDNUMBER ratingTypeFields[] = {MAIN_RATING_FIELD, MAIN_TYPE_FIELD};
  18. FIELDNUMBER cityTypeFields[] = {MAIN_CITY_FIELD, MAIN_TYPE_FIELD};
  19.  
  20.  
  21. /****************************************************************************
  22. *          
  23. * CLASS: MainRestaurant
  24. *                                                                
  25. * MEMBER FUNCTION:  MainRestaurant (constructor)
  26. *
  27. * DESCRIPTION:  This function creates an instance of a MainRestaurant
  28. *               class object.
  29. *               
  30. * RETURNS: NONE
  31. *
  32. ****************************************************************************/
  33.  
  34. MainRestaurant::MainRestaurant(BDatabase *db) : AbstractRestaurant(db)
  35. {
  36.   // 
  37.   // Set the field data members to blank.
  38.   //
  39.  
  40.   memset(name, 0, MAX_NAME_LEN + 1);
  41.   memset(type, 0, MAX_TYPE_LEN + 1);
  42.   memset(street, 0, MAX_STREET_LEN + 1);
  43.   memset(city, 0, MAX_CITY_LEN + 1);
  44.   memset(state, 0, MAX_STATE_LEN + 1);
  45.   memset(zip, 0, MAX_ZIP_LEN + 1);
  46.   memset(telephone,0, MAX_TELEPHONE_LEN + 1);
  47.   rating = 0;
  48.  
  49.   //
  50.   // Construct cursors for the composite secondary indexes.
  51.   //
  52.   ratingTypeIndex = new BCursor(); 
  53.   cityTypeIndex = new BCursor(); 
  54.   
  55. }
  56.  
  57. /****************************************************************************
  58. *          
  59. * CLASS: MainRestaurant
  60. *                                                                
  61. * MEMBER FUNCTION: ~MainRestaurant (destructor)
  62. *
  63. * DESCRIPTION:  This is the destructor for the main restaurant class.
  64. *               It will properly close a class of this type.
  65. *               
  66. * RETURNS: NONE              
  67. *
  68. ****************************************************************************/
  69.  
  70. MainRestaurant::~MainRestaurant()
  71. {
  72.   //
  73.   // Delete the BCursor objects in the class for the secondary indexes.
  74.   //
  75.   delete ratingTypeIndex;
  76.   delete cityTypeIndex;
  77. }
  78.  
  79. /****************************************************************************
  80. *          
  81. * CLASS:  MainRestaurant
  82. *                                                                
  83. * MEMBER FUNCTION: getRecord
  84. *
  85. * DESCRIPTION:  This function gets the current record from the database
  86. *               and assigns the field values to the data members in the
  87. *               class.
  88. *               
  89. *    NOTE:
  90. *
  91. *    Since BLOB fields are not stored in the table's .DB file, getting the
  92. *    record does not retrieve the BLOB field's contents. Two functions are 
  93. *    used to get a record and a BLOB field. First, one must get the record 
  94. *    and then the BLOB fields must be retrieved. Between the call to 
  95. *    getRecord() and open BlobRead(), the BLOBs record could be deleted, or
  96. *    the BLOB could be changed. If this happens, openBlobRead() will return 
  97. *    PXERR_BLOBMODIFIED.  To prevent BLOB updates while a record is being
  98. *    read, you can lock the record prior to calling getRecord() and release 
  99. *    the lock after getting the BLOB fields. 
  100. *
  101. * RETURNS: PXERR_, if one occurs.
  102. *
  103. ****************************************************************************/
  104.  
  105. Retcode MainRestaurant::getRecord()
  106. {
  107.   BRecord     *currentRecord;
  108.   LOCKHANDLE  recordLockHandle;
  109.   BOOL        isBlank;
  110.  
  111.   //
  112.   // See if the table was opened.
  113.   //
  114.   if(!isOpen)
  115.   {
  116.      return(lastError = ERROR_TABLENOTOPEN);
  117.   }
  118.  
  119.   //
  120.   // If the application is running in a multiuser environment, check to 
  121.   // see if another user has changed the table.
  122.   //
  123.   if(cursorPtr->hasChanged() == TRUE)
  124.   {
  125.     //
  126.     // Refresh the table's buffers.
  127.     //
  128.     cursorPtr->refresh();
  129.   }
  130.   //
  131.   // Reduce the amount of pointer dereference.
  132.   //
  133.   currentRecord = cursorPtr->genericRec;
  134.   //
  135.   // Close any open BLOB fields that might be open in this table.
  136.   //
  137.   currentRecord->closeBlob(MAIN_REVIEW_FIELD, FALSE);  
  138.   currentRecord->closeBlob(MAIN_MENU_FIELD, FALSE);  
  139.   // 
  140.   // Lock the record.
  141.   //
  142.   recordLockHandle = cursorPtr->lockRecord();
  143.  
  144.   //
  145.   // Check if the record is locked and the network is initialized.
  146.   //
  147.   if((cursorPtr->lastError != PXSUCCESS) &&
  148.     (cursorPtr->lastError != PXERR_NONETINIT))
  149.   {
  150.     //
  151.     // Return any error that occurred. 
  152.     //
  153.     return(lastError = cursorPtr->lastError);
  154.   }
  155.   //
  156.   // Call the base class to get the record from the table.
  157.   //
  158.   lastError = AbstractRestaurant::getRecord();
  159.   //
  160.   // Check if successful. 
  161.   //
  162.   if(lastError == PXSUCCESS)
  163.   {
  164.     //
  165.     // Use the BCursor generic record to extract the fields from the record.
  166.     //
  167.     currentRecord->getField(MAIN_NAME_FIELD, name, MAX_NAME_LEN + 1, isBlank); 
  168.     currentRecord->getField(MAIN_STREET_FIELD, street, MAX_STREET_LEN + 1,
  169.       isBlank); 
  170.     currentRecord->getField(MAIN_CITY_FIELD, city, MAX_CITY_LEN + 1, isBlank); 
  171.     currentRecord->getField(MAIN_STATE_FIELD, state, MAX_STATE_LEN + 1,
  172.       isBlank); 
  173.     currentRecord->getField(MAIN_ZIP_FIELD, zip, MAX_ZIP_LEN + 1, isBlank); 
  174.     currentRecord->getField(MAIN_TELEPHONE_FIELD, telephone, 
  175.       MAX_TELEPHONE_LEN + 1, isBlank);
  176.     currentRecord->getField(MAIN_TYPE_FIELD, type, MAX_TYPE_LEN + 1, isBlank); 
  177.     currentRecord->getField(MAIN_RATING_FIELD, rating, isBlank);
  178.  
  179.     //
  180.     // Create private BLOBs for the two memo fields.  This will prevent
  181.     // other users from changing the BLOB or deleting the record with
  182.     // which the BLOB is associated.
  183.     //
  184.     currentRecord->openBlobRead(MAIN_MENU_FIELD, TRUE);
  185.     currentRecord->openBlobRead(MAIN_REVIEW_FIELD, TRUE);
  186.   }
  187.   //
  188.   // Unlock the record.
  189.   //
  190.   cursorPtr->unlockRecord(recordLockHandle);
  191.  
  192.   return(lastError);
  193. }
  194.  
  195. /****************************************************************************
  196. *          
  197. * CLASS:  MainRestaurant
  198. *                                                                
  199. * MEMBER FUNCTION: getQuickReview
  200. *
  201. * DESCRIPTION:  This function gets the header (first 80 bytes) of the Review
  202. *               field in the record.  
  203. *               
  204. * RETURNS: PXERR_, if one occurs.
  205. *
  206. ****************************************************************************/
  207.  
  208. Retcode MainRestaurant::getQuickReview(char *buffer, int sizeOfBuffer, 
  209.   int &bytesRead)
  210. {
  211.   //
  212.   // Use a generic function to retrieve the BLOB header.
  213.   //
  214.   lastError = getQuickBlob(MAIN_REVIEW_FIELD, buffer, sizeOfBuffer, 
  215.     bytesRead);
  216.  
  217.   return(lastError);
  218.  
  219. }
  220.  
  221. /****************************************************************************
  222. *          
  223. * CLASS:  MainRestaurant
  224. *                                                                
  225. * MEMBER FUNCTION: getReview
  226. *
  227. * DESCRIPTION:  This function gets the review field from the table.
  228. *               It skips the first 80 bytes of the field which provides
  229. *               a quick review of the field's contents.
  230. *               
  231. * RETURNS: PXERR_, if one occurs.
  232. *
  233. ****************************************************************************/
  234.  
  235. Retcode MainRestaurant::getReview(char *buffer, unsigned int sizeOfBuffer, 
  236.   long offset, unsigned int &bytesRead)
  237. {
  238.   //
  239.   // Specify particular field and use more generic getBlobField function.
  240.   // Offset past the quick review size so the header is not duplicated when
  241.   // getting the review.
  242.   //
  243.   lastError = getBlobField(MAIN_REVIEW_FIELD, buffer, sizeOfBuffer, 
  244.     offset + MAX_REVIEW_SIZE, bytesRead);
  245.  
  246.   return(lastError);
  247.  
  248. }
  249.  
  250. /****************************************************************************
  251. *          
  252. * CLASS:  MainRestaurant
  253. *                                                                
  254. * MEMBER FUNCTION: getMenu
  255. *
  256. * DESCRIPTION:  This function gets the menu field from the table.
  257. *               
  258. * RETURNS: PXERR_, if one occurs.
  259. *
  260. ****************************************************************************/
  261.  
  262. Retcode MainRestaurant::getMenu(char *buffer, unsigned int sizeOfBuffer, 
  263.   long offset, unsigned int &bytesRead) 
  264. {
  265.   //
  266.   // Specify a particular field and use the generic get BLOB field function.
  267.   //
  268.   lastError = getBlobField(MAIN_MENU_FIELD, buffer, sizeOfBuffer, offset,
  269.     bytesRead);
  270.  
  271.   return(lastError);
  272. }
  273.  
  274. /****************************************************************************
  275. *          
  276. * CLASS: MainRestaurant
  277. *                                                                
  278. * MEMBER FUNCTION: sizeOfReviewBlob
  279. *
  280. * DESCRIPTION: This function returns the size of the REVIEW memo field.
  281. *               
  282. * RETURNS: Number of bytes in the REVIEW memo field.
  283. *
  284. ****************************************************************************/
  285.  
  286. long MainRestaurant::sizeOfReviewBlob()
  287. {
  288.  
  289.   //
  290.   // Return the BLOB size. Error checking done in base function.
  291.   //
  292.   return(getBlobSize(MAIN_REVIEW_FIELD));
  293.  
  294. }
  295.  
  296. /****************************************************************************
  297. *          
  298. * CLASS: MainRestaurant
  299. *                                                                
  300. * MEMBER FUNCTION: sizeOfMenuBlob
  301. *
  302. * DESCRIPTION: This function returns the size of the MENU memo field.
  303. *               
  304. * RETURNS: Number of bytes in the MENU memo field.
  305. *
  306. ****************************************************************************/
  307.  
  308. long MainRestaurant::sizeOfMenuBlob()
  309. {
  310.   //
  311.   // Return the BLOB size. Error checking done in base function.
  312.   //
  313.   return(getBlobSize(MAIN_MENU_FIELD));
  314.  
  315. }
  316.  
  317. /****************************************************************************
  318. *          
  319. * CLASS: MainRestaurant
  320. *                                                                
  321. * MEMBER FUNCTION: open
  322. *
  323. * DESCRIPTION: This function opens the primary table and also opens the
  324. *              secondary indexes needed for this table.
  325. *              
  326. * RETURNS: PXERR_, if one occurs.
  327. *
  328. ****************************************************************************/
  329.  
  330. Retcode MainRestaurant::open(char *tableName)
  331. {
  332.   FIELDNUMBER ratingTypeIndexId;
  333.   FIELDNUMBER cityTypeIndexId;
  334.  
  335.   //
  336.   // Call the base class open() function to open the primary index.
  337.   //
  338.   lastError = AbstractRestaurant::open(tableName);
  339.   //
  340.   // Check if successful. 
  341.   //
  342.   if(lastError == PXSUCCESS)
  343.   {
  344.     //
  345.     // Create index ID for the rating-type index.
  346.     //
  347.     lastError = dataBase->defineCompoundKey(tableName, RATING_TYPE_FLDCOUNT, 
  348.       ratingTypeFields, RATING_TYPE_INDEX, FALSE, ratingTypeIndexId);
  349.  
  350.     //
  351.     // Create index ID for the city-type index. This index is
  352.     // case-sensititive.
  353.     //
  354.     lastError = dataBase->defineCompoundKey(tableName, CITY_TYPE_FLDCOUNT, 
  355.       cityTypeFields, CITY_TYPE_INDEX, TRUE, cityTypeIndexId);
  356.     //
  357.     // Open the cursor for the rating-type index.
  358.     //
  359.     ratingTypeIndex->open(dataBase, tableName, ratingTypeIndexId, FALSE);
  360.     //
  361.     // Open the cursor for the city-type index.
  362.     //
  363.     cityTypeIndex->open(dataBase, tableName, cityTypeIndexId, FALSE);
  364.   }
  365.   return(lastError);
  366. }
  367.  
  368. /****************************************************************************
  369. *          
  370. * CLASS: MainRestaurant
  371. *                                                                
  372. * MEMBER FUNCTION: close
  373. *
  374. * DESCRIPTION: This function closes the primary table and also closes the
  375. *              secondary indexes used by this table.
  376. *              
  377. * RETURNS: PXERR_, if one occurs.
  378. *
  379. ****************************************************************************/
  380.  
  381. Retcode MainRestaurant::close()
  382. {
  383.   //
  384.   // Call the base class open() function to open the primary index.
  385.   //
  386.   lastError = AbstractRestaurant::close();
  387.   //
  388.   // Check if successful. 
  389.   //
  390.   if(lastError == PXSUCCESS)
  391.   {
  392.     //
  393.     // Close the secondary indexes.
  394.     //  
  395.     ratingTypeIndex->close();
  396.     cityTypeIndex->close();
  397.   }
  398.   return(lastError);
  399. }
  400.  
  401. /****************************************************************************
  402. *          
  403. * CLASS: MainRestaurant
  404. *                                                                
  405. * MEMBER FUNCTION: copyToFavorite
  406. *
  407. * DESCRIPTION: This function will copy the current record of the main 
  408. *              restaurant table to the favorite restuarant table.
  409. *               
  410. * RETURNS: PXERR_, if one occurs.
  411. *
  412. ****************************************************************************/
  413.  
  414. Retcode MainRestaurant::copyToFavorite(FavoriteRestaurant &placeHere)
  415. {
  416.   BRecord favoriteRecord(placeHere.cursorPtr);
  417.  
  418.   char menuBuffer[BLOB_COPY_LEN + 1];
  419.  
  420.   unsigned int menuBytesRead;
  421.  
  422.   long menuOffset;
  423.   long menuSize;
  424.  
  425.   //
  426.   // Get the current record.
  427.   //
  428.   lastError = getRecord();
  429.  
  430.   //
  431.   // Check if successful. 
  432.   //
  433.   if(lastError == PXSUCCESS)
  434.   {
  435.     //
  436.     // Determine if the favorite table is open.
  437.     //
  438.     if(placeHere.isOpen == FALSE)
  439.     {
  440.       lastError = ERROR_TABLENOTOPEN;
  441.     }
  442.     else
  443.     {
  444.       //
  445.       // Place the field values (name and type) into the favorite table's 
  446.       // record buffer.
  447.       //
  448.       favoriteRecord.putField(FAV_NAME_FIELD, name);
  449.       favoriteRecord.putField(FAV_TYPE_FIELD, type);
  450.  
  451.       //
  452.       // Get the size of the menu memo.
  453.       //
  454.       menuSize = sizeOfMenuBlob();
  455.  
  456.       //  
  457.       // Determine if the menu field needs to be copied.
  458.       //
  459.       if(menuSize != 0)
  460.       {
  461.         //
  462.         // Open the BLOB in the favorite record buffer in write mode and
  463.         // allocate the size of the menu memo.
  464.         //
  465.         //favoriteRecord.openBlobWrite(FAV_MENU_FIELD, menuSize, TRUE);
  466.         // ms changed PXBLOBCOPY to PXBLOBNEW
  467.         favoriteRecord.openBlobWrite(FAV_MENU_FIELD, menuSize, FALSE);
  468.  
  469.         //
  470.         // Read BLOB_COPY_LEN bytes of the menu field and write 
  471.         // it to the menu field in the favorite restaurant table.
  472.         //
  473.         for(menuOffset = 0; menuOffset < menuSize; 
  474.           menuOffset += BLOB_COPY_LEN)
  475.         {
  476.           //
  477.           // Read the BLOB from the main table. Use the getMenu() member
  478.           // function.
  479.           //
  480.           getMenu(menuBuffer, BLOB_COPY_LEN + 1, menuOffset, menuBytesRead);
  481.           
  482.           //
  483.           // Write it to the favorite restaurant record buffer.
  484.           //
  485.           favoriteRecord.putBlob(FAV_MENU_FIELD, menuBytesRead, menuOffset,
  486.             menuBuffer);
  487.         }
  488.         //
  489.         // Close the BLOB and accept the changes.
  490.         //
  491.         favoriteRecord.closeBlob(FAV_MENU_FIELD, TRUE);
  492.       }
  493.       //
  494.       // Append this record to the end of the favorite restaurant table.
  495.       //
  496.       lastError = placeHere.cursorPtr->appendRec(&favoriteRecord);
  497.     }
  498.   }
  499.   return(lastError);
  500. }
  501.  
  502. /****************************************************************************
  503. *          
  504. * CLASS: MainRestaurant
  505. *                                                                
  506. * MEMBER FUNCTION: findRatingType
  507. *
  508. * DESCRIPTION: This function locates a restaurant by Rating and Type using 
  509. *              a composite index. 
  510. *
  511. * RETURNS: PXERR_, if one occurs.
  512. *
  513. ****************************************************************************/
  514.  
  515. Retcode MainRestaurant::findRatingType(int ratingToFind, char *typeToFind, 
  516.   PXSearchMode searchMode)
  517. {
  518.   BRecord searchRecord(ratingTypeIndex);
  519.   BRecord *currentRecord;
  520.  
  521.   if(!isOpen)
  522.   {
  523.      return(lastError = ERROR_TABLENOTOPEN);
  524.   }
  525.   //
  526.   // Specify the rating you want to find in the Rating field.
  527.   //
  528.   searchRecord.putField(MAIN_RATING_FIELD, (short)ratingToFind);
  529.  
  530.   //
  531.   // Specify the type you want to find in the Type field.
  532.   //
  533.   searchRecord.putField(MAIN_TYPE_FIELD, typeToFind);
  534.  
  535.   //
  536.   // Search the rating-type index for the specified values.
  537.   //
  538.   lastError = ratingTypeIndex->searchIndex(&searchRecord, searchMode, 
  539.     RATING_TYPE_FLDCOUNT);
  540.  
  541.   //
  542.   // Determine if the search located a record.
  543.   //
  544.   if(lastError == PXSUCCESS)
  545.   {
  546.     currentRecord = cursorPtr->genericRec;
  547.  
  548.     //
  549.     // Close any open BLOB fields that might be open for this table. These
  550.     // BLOB fields must be closed because the function setToCursor() in the
  551.     // BCursor class uses the generic record to do the search.
  552.     //
  553.     currentRecord->closeBlob(MAIN_REVIEW_FIELD, FALSE);  
  554.     currentRecord->closeBlob(MAIN_MENU_FIELD, FALSE);  
  555.     //
  556.     // Use setToCursor() to synchronize the main cursor with the  
  557.     // secondary index cursor. 
  558.     //
  559.     lastError = cursorPtr->setToCursor(ratingTypeIndex);
  560.   }
  561.   //
  562.   // Return any error that occurs.
  563.   //
  564.   return(lastError);
  565.   
  566. }
  567.  
  568. /****************************************************************************
  569. *          
  570. * CLASS: MainRestaurant
  571. *                                                                
  572. * MEMBER FUNCTION: findCityType 
  573. *
  574. * DESCRIPTION: This function locates a restaurant by City and Type using a 
  575. *              composite index
  576. *
  577. * RETURNS: PXERR_, if one occurs.
  578. *
  579. ****************************************************************************/
  580.  
  581. Retcode MainRestaurant::findCityType(char *cityToFind, char *typeToFind, 
  582.   PXSearchMode searchMode)
  583. {
  584.   BRecord searchRecord(cityTypeIndex);
  585.   BRecord *currentRecord;
  586.  
  587.   if(!isOpen)
  588.   {
  589.      return(lastError = ERROR_TABLENOTOPEN);
  590.   }
  591.   //
  592.   // Specify city to find in the City field.
  593.   //
  594.   searchRecord.putField(MAIN_CITY_FIELD, cityToFind);
  595.  
  596.   //
  597.   // Specify the type to find in the Type field.
  598.   //
  599.   searchRecord.putField(MAIN_TYPE_FIELD, typeToFind);
  600.  
  601.   //
  602.   // Search the city-type index for the specified values.
  603.   //
  604.   lastError = cityTypeIndex->searchIndex(&searchRecord, searchMode, 
  605.     CITY_TYPE_FLDCOUNT);
  606.   //
  607.   // Determine if the search located a record.
  608.   //
  609.   if(lastError == PXSUCCESS)
  610.   {
  611.     currentRecord = cursorPtr->genericRec;
  612.     //
  613.     // Close any open BLOB fields that might be open for this table. These
  614.     // BLOB fields must be closed because the function setToCursor() in the
  615.     // BCursor class uses the generic record to do the search.
  616.     //
  617.     currentRecord->closeBlob(MAIN_REVIEW_FIELD, FALSE);  
  618.     currentRecord->closeBlob(MAIN_MENU_FIELD, FALSE);  
  619.     //
  620.     // Use setToCursor() to synchronize the main cursor with the  
  621.     // secondary index cursor. 
  622.     //
  623.     lastError = cursorPtr->setToCursor(cityTypeIndex);
  624.   }
  625.   //
  626.   // Return any error that occurred.
  627.   //
  628.   return(lastError);
  629. }
  630.