home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / blt2_214.zip / src / bd_upd.c < prev    next >
C/C++ Source or Header  |  1996-10-16  |  13KB  |  475 lines

  1.  
  2. /* bd_upd.c -  1-Oct-1996 Cornel Huth
  3.  * This module is called by bd_main.c
  4.  * UPDATE_XB
  5.  */
  6.  
  7. #include "platform.h"
  8.  
  9. // external to this module
  10.  
  11. void PutMsg(CHAR *strg);
  12. void GetMsg(CHAR *strg);
  13.  
  14. extern CHAR *collateTable;
  15.  
  16. #if FOR_WINDOWS == 1
  17.  void DoWinThing(int waitFlag);
  18. #endif
  19.  
  20. // public in this module
  21.  
  22. int bd_upd(void);
  23.  
  24. // GO
  25.  
  26. int bd_upd(void) {
  27.  
  28. void BuildFieldListUpd(FIELDDESCTYPE fieldList[]);
  29.  
  30. #pragma pack(1)
  31.  
  32.  ACCESSPACK AP;
  33.  DOSFILEPACK DFP;
  34.  CREATEDATAPACK CDP;
  35.  CREATEINDEXPACK CIP;
  36.  HANDLEPACK HP;
  37.  OPENPACK OP;
  38.  
  39.  struct EmpRecType {
  40.   CHAR tag;              // record tag, init to SPACE, * means deleted
  41.   CHAR empID[9];         // SSN (not 0T string)
  42.   CHAR empLN[16];        // last name
  43.   CHAR empFN[16];        // first name
  44.   CHAR empHire[8];       // "YYYYMMDD" (not 0T string)
  45.   CHAR empDept[6];       // department assigned
  46.  }; // 56 bytes
  47.  struct EmpRecType EmpRec;
  48.  
  49. #pragma pack()
  50.  
  51.  time_t startTime, endTime;
  52.  int display = 0;                // display results or not flag
  53.  int sameSequence = 1;           // use same random seed each time
  54.  int rndSeqVar = 0;              // random "key" generated (9 digits worth)
  55.  int doOptimize = 1;             // optimize index prior update and key access
  56.  LONG rez;                       // return value from Bullet
  57.  
  58.  CHAR nameIX3[] = ".\\$bd_upd.ix3"; // name of index file created
  59.  ULONG indexID=0;                // handle of index file
  60.  CHAR keyExpression[128];        // key expression string buffer (159 max)
  61.  CHAR keyBuffer[68];             // buffer used to store/receive key values
  62.  
  63.  CHAR nameData[] = ".\\$bd_upd.dbf";// name of data file created
  64.  ULONG dataID=0;                 // handle of data file
  65.  FIELDDESCTYPE fieldList[5];     // 5 fields used in data record
  66.  
  67.  LONG recs2add;          // records to add
  68.  LONG i;                 // counter
  69.  LONG recNo;             // counter
  70.  CHAR tmpStr[128];       // misc stuff, non-Bullet related
  71.  CHAR putStr[128];
  72.  
  73.  PutMsg("UPDATE_XB, an all-or-nothing transaction update into up to\n");
  74.  PutMsg("256 files from a single call.\n\n");
  75.  
  76.  // Implicit is the tag field at the first byte, then comes...
  77.  
  78.  memset(fieldList,0,sizeof(fieldList));  // init unused bytes to 0 (required)
  79.  BuildFieldListUpd(fieldList);
  80.  
  81.  // Delete previous files from any previous run (disregard any error return)
  82.  
  83.  DFP.func = DELETE_FILE_DOS;
  84.  DFP.filenamePtr = nameData;
  85.  rez = BULLET(&DFP);
  86.  DFP.filenamePtr = nameIX3;
  87.  rez = BULLET(&DFP);
  88.  
  89.  
  90.  // Create the data file, a standard DBF (ID=3) as defined in fieldList above.
  91.  
  92.  CDP.func = CREATE_DATA_XB;
  93.  CDP.filenamePtr = nameData;
  94.  CDP.noFields = 5;
  95.  CDP.fieldListPtr = fieldList;
  96.  CDP.fileID = 0x03;
  97.  rez = BULLET(&CDP);
  98.  if (rez) {
  99.     sprintf(putStr,"Failed data file create.  Err: %d\n",rez);
  100.     PutMsg(putStr);
  101.     goto Abend;
  102.  }
  103.  
  104.  
  105.  // Open the data file (required before creating an index file for it)
  106.  
  107.  OP.func = OPEN_DATA_XB;
  108.  OP.filenamePtr = nameData;
  109.  OP.asMode = READWRITE | DENYNONE;
  110.  rez = BULLET(&OP);
  111.  if (rez) {
  112.     sprintf(putStr,"Failed data file open.  Err: %d\n",rez);
  113.     PutMsg(putStr);
  114.     goto Abend;
  115.  }
  116.  dataID = OP.handle;
  117.  
  118.  // Create an index file for the data file opened above.
  119.  // This example uses a single, 9-byte key -- the SSN.
  120.  
  121.  strcpy(keyExpression,"SSN");
  122.  
  123.  CIP.func = CREATE_INDEX_XB;
  124.  CIP.filenamePtr = nameIX3;
  125.  CIP.keyExpPtr = keyExpression;
  126.  CIP.xbLink = dataID;            // the handle of the data file
  127.  CIP.sortFunction = ASCII_SORT;  // sort by ASCII order (fine for text numbers)
  128.  CIP.codePage = CODEPAGE;        // code page
  129.  CIP.countryCode = CTRYCODE;     // country code
  130.  CIP.collatePtr = NULL;          // since ASCII_SORT, no collate table
  131.  CIP.nodeSize = 512;             // 512-byte node size (or 1024, 2048 bytes)
  132.  rez = BULLET(&CIP);
  133.  if (rez) {
  134.     sprintf(putStr,"Failed index file create.  Err: %d\n",rez);
  135.     PutMsg(putStr);
  136.     goto Abend;
  137.  }
  138.  
  139.  
  140.  // Open the index file (what we just created above).
  141.  
  142.  OP.func = OPEN_INDEX_XB;
  143.  OP.filenamePtr = nameIX3;
  144.  OP.asMode = READWRITE | DENYNONE;
  145.  OP.xbLink = dataID;
  146.  rez = BULLET(&OP);
  147.  if (rez) {
  148.     sprintf(putStr,"Failed index file open.  Err: %d\n",rez);
  149.     PutMsg(putStr);
  150.     goto Abend;
  151.  }
  152.  indexID = OP.handle;
  153.  
  154.  PutMsg("Display all data accessed (slower results)? (y/N) ");
  155.  GetMsg(tmpStr);
  156.  if (*tmpStr=='y') display = 1;
  157.  
  158.  PutMsg("           Repeat same random key sequence? (Y/n) ");
  159.  GetMsg(tmpStr);
  160.  if (*tmpStr=='n') sameSequence = 0;
  161.  
  162.  PutMsg("               Optimize index after update? (Y/n) ");
  163.  GetMsg(tmpStr);
  164.  if (*tmpStr=='n') doOptimize = 0;
  165.  
  166.  PutMsg("  How many records do you want for this test run? ");
  167.  GetMsg(tmpStr);
  168.  recs2add = atol(tmpStr);
  169.  if (recs2add < 1) recs2add = 1;  // would you rather end the test?
  170.  if (recs2add > 9999999) recs2add = 1; // why wait around for 10M?
  171.  
  172.  // Add the data records, which are created here, on-the-fly, varying enough
  173.  // to make unique records.  The key is inserted for each record added.
  174.  
  175.  EmpRec.tag = ' ';                       // set to not-deleted
  176.  strncpy(EmpRec.empID,"000000000",9);    // the key.field
  177.  strcpy(EmpRec.empLN,"YourLastName");    // everyone has the same last name
  178.  strcpy(EmpRec.empFN,"YourFirstName");   // everyone has this first name!
  179.  strncpy(EmpRec.empHire,"19950618",8);   // YYYYMMDD DBF form, no \0 on date
  180.  strcpy(EmpRec.empDept,"MIS");           // everyone works for MIS!
  181.  
  182.  // The record construction creates a pretty random SSN number (.empID)
  183.  // and that is used as the key -- the key is kept unique (i.e., duplicate
  184.  // .empID values are not allowed).  In case of a duplicate (likely given
  185.  // the SSN generation technque), the changes made to the database are
  186.  // backed out by BULLET.  Another insert is made to cover the count requested.
  187.  
  188.  if (sameSequence)
  189.     srand(1);
  190.  else
  191.     srand((unsigned)time(0));
  192.  
  193.  sprintf(putStr,"Inserting %d recs/keys... ",recs2add);
  194.  PutMsg(putStr);
  195.  time(&startTime);
  196.  
  197.  AP.func = INSERT_XB;
  198.  AP.handle = indexID;
  199.  AP.keyPtr = keyBuffer;
  200.  AP.recPtr = &EmpRec;
  201.  AP.nextPtr = NULL;
  202.  
  203.  for (i = 1; i <= recs2add; i++) {
  204.  
  205.     rndSeqVar = (rand() >> 1) * (rand() >> 2);   // 16383*8191=134193153 max
  206.     sprintf(tmpStr,"%9.9i",rndSeqVar);
  207.     strncpy(EmpRec.empID,tmpStr,9);              // update SSN
  208.  
  209.     AP.recNo = 0;
  210.  
  211.     rez = BULLET(&AP);
  212.     if (rez) {
  213.  
  214.        // negative rc means failed during data record add
  215.  
  216.        if (rez < 0) {
  217.           rez = AP.stat;
  218.           sprintf(putStr,"Failed during data portion, sequence %d.  Err: %d\n",i,rez);
  219.           PutMsg(putStr);
  220.           goto Abend;
  221.        }
  222.  
  223.        // otherwise during index key insert
  224.  
  225.        else {
  226.           rez = AP.stat;
  227.           if (rez == EXB_KEY_EXISTS) {
  228.              rez = 0;
  229.              i--;
  230.           }
  231.           else {
  232.              sprintf(putStr,"Failed during index portion, sequence %d.  Err: %d\n",i,rez);
  233.              PutMsg(putStr);
  234.              goto Abend;
  235.           }
  236.        }
  237.     }
  238.  
  239. #if FOR_WINDOWS == 1                   // deal with message queue every now and then
  240.     if (i % Q_INS == 0) DoWinThing(0); // 0=no waiting around
  241. #endif
  242.  
  243.  }
  244.  time(&endTime);
  245.  sprintf(putStr,"took %u secs.\n",(endTime - startTime));
  246.  PutMsg(putStr);
  247.  
  248.  PutMsg("\nUpdating the entire database by adding 200000000 to key field\n");
  249.  sprintf(putStr," Updating %d recs/keys... ",recs2add);
  250.  PutMsg(putStr);
  251.  time(&startTime);
  252.  
  253.  recNo=1;
  254.  AP.func = GET_RECORD_XB;        // direct access, see above notes
  255.  AP.handle = dataID;             // GET_RECORD_XB uses only the data file
  256.  AP.recNo = recNo;               // get the first record to start
  257.  AP.keyPtr = keyBuffer;          // ...to be used by UPDATE_XB
  258.  AP.recPtr = &EmpRec;
  259.  AP.nextPtr = NULL;
  260.  rez = BULLET(&AP);
  261.  i=0;
  262.  
  263.  while (rez==0) {
  264.  
  265.     // got the data record, force a key update by changing key field
  266.     // all this does is change the first digit of the nine, same effect
  267.     // as adding 200000000
  268.  
  269.     *(EmpRec.empID)+=2;
  270.  
  271.     AP.func = UPDATE_XB;
  272.     AP.handle = indexID;
  273.     rez = BULLET(&AP);
  274.     if (rez) {
  275.        if (rez < 0) {
  276.           rez = AP.stat;
  277.           sprintf(putStr,"Failed data update, rec#: %d. Err: %d\n",AP.recNo,rez);
  278.           PutMsg(putStr);
  279.           goto Abend;
  280.        }
  281.  
  282.        // otherwise during index key update
  283.  
  284.        else {
  285.           rez = AP.stat;
  286.           sprintf(putStr,"Failed index update, rec#: %d. Err: %d\n",AP.recNo,rez);
  287.           PutMsg(putStr);
  288.           goto Abend;
  289.        }
  290.     }
  291.     i++;
  292.  
  293.     // change for GET_RECORD_XB...
  294.  
  295.     AP.func = GET_RECORD_XB;
  296.     AP.handle = dataID;
  297.     AP.recNo=++recNo;
  298.     rez = BULLET(&AP);
  299.  
  300. #if FOR_WINDOWS == 1                   // deal with message queue every now and then
  301.     if (i % Q_UPD == 0) DoWinThing(0); // 0=no waiting around
  302. #endif
  303.  
  304.  }
  305.  time(&endTime);
  306.  
  307.  // expected error is EXB_BAD_RECNO
  308.  
  309.  if (rez == EXB_BAD_RECNO) rez=0;
  310.  if (rez) {
  311.     sprintf(putStr,"Failed GET_RECORD_XB at %d.  Err: %d\n",AP.recNo,rez);
  312.     PutMsg(putStr);
  313.     goto Abend;
  314.  }
  315.  sprintf(putStr,"took %u secs. for %d updates\n",(endTime - startTime),i);
  316.  PutMsg(putStr);
  317.  
  318.  // all records now are > 200000000, as are their keys
  319.  
  320.  if (doOptimize) {
  321.     PutMsg("Optimizing index... (no callback in this example)");
  322.     AP.func = REINDEX_XB;        // this is all there is to reindexing even...
  323.     AP.handle = indexID;         // ...million-record databases
  324.     AP.keyPtr = keyBuffer;       // if dup key error...(see manual for details)
  325.     AP.nextPtr = NULL;           // just this one index file
  326.     rez = BULLET(&AP);
  327.     if (rez)  {
  328.        rez = AP.stat;
  329.        sprintf(putStr,"Failed optimize (reindex).  Err: %d\n",rez);
  330.        PutMsg(putStr);
  331.        goto Abend;
  332.     }
  333.     PutMsg("Done\n");
  334.  }
  335.  
  336.  memset(keyBuffer,0,sizeof(keyBuffer));
  337.  
  338.  sprintf(putStr," Accessing %d keys...     ",recs2add);
  339.  PutMsg(putStr);
  340.  if (display) PutMsg("\n");
  341.  
  342.  time(&startTime);
  343.  AP.func = FIRST_KEY_XB;
  344.  AP.handle = indexID;
  345.  AP.keyPtr = keyBuffer;
  346.  rez = BULLET(&AP);
  347.  i=0;
  348.  while (rez==0) {
  349.     i++;
  350.     if (display) {
  351.        sprintf(putStr,"%s  %9.9u\r", keyBuffer, AP.recNo);
  352.        PutMsg(putStr);
  353.     }
  354.     AP.func = NEXT_KEY_XB;
  355.     rez = BULLET(&AP);
  356.  
  357. #if FOR_WINDOWS == 1                   // deal with message queue every now and then
  358.     if (i % Q_KEY == 0) DoWinThing(0); // 0=no waiting around
  359. #endif
  360.  
  361.  }
  362.  time(&endTime);
  363.  if (display) PutMsg("\n...");
  364.  
  365.  // expected rez is ERR_END_OF_FILE
  366.  
  367.  if (rez == EXB_END_OF_FILE) rez=0;
  368.  if (rez) {
  369.     sprintf(putStr,"Failed KEY access.  Err: %d\n",rez);
  370.     PutMsg(putStr);
  371.     goto Abend;
  372.  }
  373.  sprintf(putStr,"took %u secs. for %d keys\n",(endTime - startTime),i);
  374.  PutMsg(putStr);
  375.  
  376.  sprintf(putStr," Accessing %d keys+recs...",recs2add);
  377.  PutMsg(putStr);
  378.  if (display) PutMsg("\n");
  379.  
  380.  time(&startTime);
  381.  AP.func = GET_FIRST_XB;
  382.  AP.handle = indexID;
  383.  AP.keyPtr = keyBuffer;
  384.  AP.recPtr = &EmpRec;
  385.  rez = BULLET(&AP);
  386.  i=0;
  387.  while (rez==0) {
  388.     i++;
  389.     if (display) {
  390.        sprintf(putStr,"%s  %9.9u   %s\r", keyBuffer, AP.recNo, &EmpRec);
  391.        PutMsg(putStr);
  392.     }
  393.     AP.func = GET_NEXT_XB;
  394.     rez = BULLET(&AP);
  395.  
  396. #if FOR_WINDOWS == 1                   // deal with message queue every now and then
  397.     if (i % Q_GET == 0) DoWinThing(0); // 0=no waiting around
  398. #endif
  399.  
  400.  }
  401.  time(&endTime);
  402.  if (display) PutMsg("\n...");
  403.  
  404.  // expected rez is ERR_END_OF_FILE
  405.  
  406.  if (rez == EXB_END_OF_FILE) rez=0;
  407.  if (rez) {
  408.     sprintf(putStr,"Failed GET access.  Err: %d\n",rez);
  409.     PutMsg(putStr);
  410.     goto Abend;
  411.  }
  412.  sprintf(putStr,"took %u secs. for %d keys & records\n",(endTime - startTime),i);
  413.  PutMsg(putStr);
  414.  
  415.  // Fatal errors above come straight to here
  416.  Abend:
  417.  
  418.  // Close files
  419.  
  420.  if (indexID) {
  421.     HP.func = CLOSE_INDEX_XB;
  422.     HP.handle = indexID;
  423.     rez = BULLET(&HP);
  424.     if (rez) {
  425.        sprintf(putStr,"Failed index file close.  Err: %d\n",rez);
  426.        PutMsg(putStr);
  427.     }
  428.  }
  429.  
  430.  if (dataID) {
  431.     HP.func = CLOSE_DATA_XB;
  432.     HP.handle = dataID;
  433.     rez = BULLET(&HP);
  434.     if (rez) {
  435.        sprintf(putStr,"Failed data file close.  Err: %d\n",rez);
  436.        PutMsg(putStr);
  437.     }
  438.  }
  439.  
  440.  return rez;
  441. }
  442.  
  443.  
  444. //------------------------------------
  445. // Init field list items for data file
  446.  
  447. void BuildFieldListUpd(FIELDDESCTYPE fieldList[]) {
  448.  
  449.  strcpy(fieldList[0].fieldName, "SSN");
  450.  fieldList[0].fieldType = 'C';
  451.  fieldList[0].fieldLen = 9;
  452.  fieldList[0].fieldDC = 0;
  453.  
  454.  strcpy(fieldList[1].fieldName, "LNAME");
  455.  fieldList[1].fieldType = 'C';
  456.  fieldList[1].fieldLen = 16;
  457.  fieldList[1].fieldDC = 0;
  458.  
  459.  strcpy(fieldList[2].fieldName, "FNAME");
  460.  fieldList[2].fieldType = 'C';
  461.  fieldList[2].fieldLen = 16;
  462.  fieldList[2].fieldDC = 0;
  463.  
  464.  strcpy(fieldList[3].fieldName, "HIRED");
  465.  fieldList[3].fieldType = 'D';
  466.  fieldList[3].fieldLen = 8;      // date field type must be 8.0
  467.  fieldList[3].fieldDC = 0;
  468.  
  469.  strcpy(fieldList[4].fieldName, "DEPT");
  470.  fieldList[4].fieldType = 'C';
  471.  fieldList[4].fieldLen = 6;
  472.  fieldList[4].fieldDC = 0;
  473.  return;
  474. }
  475.