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

  1.  
  2. /* bd_ins.c - 30-Sep-1996 Cornel Huth
  3.  * This module is called by bd_main.c
  4.  * INSERT_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_ins(void);
  23.  
  24. // GO
  25.  
  26. int bd_ins(void) {
  27.  
  28. void BuildFieldListIns(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.  
  56.  LONG rez;                       // return value from Bullet
  57.  
  58.  CHAR nameIX3[] = ".\\$bd_ins.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_ins.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 en-masse
  68.  LONG i;                 // counter
  69.  CHAR tmpStr[128];       // misc stuff, non-Bullet related
  70.  CHAR putStr[128];
  71.  
  72.  PutMsg("INSERT_XB, an all-or-nothing transaction insert into up to\n");
  73.  PutMsg("256 files from a single call.\n\n");
  74.  
  75.  // note that this particular example uses only a single index/data file DB
  76.  
  77.  memset(fieldList,0,sizeof(fieldList));  // init unused bytes to 0 (required)
  78.  BuildFieldListIns(fieldList);
  79.  
  80.  // Delete previous files from any previous run (disregard any error return)
  81.  
  82.  DFP.func = DELETE_FILE_DOS;
  83.  DFP.filenamePtr = nameData;
  84.  rez = BULLET(&DFP);
  85.  DFP.filenamePtr = nameIX3;
  86.  rez = BULLET(&DFP);
  87.  
  88.  
  89.  // Create the data file, a standard DBF (ID=3) as defined in fieldList above.
  90.  
  91.  CDP.func = CREATE_DATA_XB;
  92.  CDP.filenamePtr = nameData;
  93.  CDP.noFields = 5;
  94.  CDP.fieldListPtr = fieldList;
  95.  CDP.fileID = 0x03;
  96.  rez = BULLET(&CDP);
  97.  if (rez) {
  98.     sprintf(putStr,"Failed data file create.  Err: %d\n",rez);
  99.     PutMsg(putStr);
  100.     goto Abend;
  101.  }
  102.  
  103.  
  104.  // Open the data file (required before creating an index file for it)
  105.  
  106.  OP.func = OPEN_DATA_XB;
  107.  OP.filenamePtr = nameData;
  108.  OP.asMode = READWRITE | DENYNONE;
  109.  rez = BULLET(&OP);
  110.  if (rez) {
  111.     sprintf(putStr,"Failed data file open.  Err: %d\n",rez);
  112.     PutMsg(putStr);
  113.     goto Abend;
  114.  }
  115.  dataID = OP.handle;
  116.  
  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;          // -- ASCII_SORT, no collate table is used
  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.  
  155.  // Have created and opened both data file and index files.
  156.  // The next section inserts record and key with the single call, and removes
  157.  // them (or any changes) if and error occured along the way.
  158.  
  159.  PutMsg("Display all data accessed (slower results)? (y/N) ");
  160.  GetMsg(tmpStr);
  161.  if (*tmpStr=='y') display = 1;
  162.  
  163.  PutMsg("           Repeat same random key sequence? (Y/n) ");
  164.  GetMsg(tmpStr);
  165.  if (*tmpStr=='n') sameSequence = 0;
  166.  
  167.  PutMsg("  How many records do you want for this test run? ");
  168.  GetMsg(tmpStr);
  169.  recs2add = atol(tmpStr);
  170.  if (recs2add < 1) recs2add = 1;  // would you rather end the test?
  171.  if (recs2add > 9999999) recs2add = 1; // why wait around for 10M?
  172.  
  173.  // Add the data records, which are created here, on-the-fly, varying enough
  174.  // to make unique records.  The key is inserted for each record added.
  175.  
  176.  // setup invariant parts of data record out of loop
  177.  
  178.  EmpRec.tag = ' ';                       // set to not-deleted
  179.  strncpy(EmpRec.empID,"000000000",9);    // the key.field
  180.  strcpy(EmpRec.empLN,"YourLastName");    // everyone has the same last name
  181.  strcpy(EmpRec.empFN,"YourFirstName");   // everyone has this first name!
  182.  strncpy(EmpRec.empHire,"19950618",8);   // YYYYMMDD DBF form, no \0 on date
  183.  strcpy(EmpRec.empDept,"MIS");           // everyone works for MIS!
  184.  
  185.  // The record construction creates a pretty random SSN number (.empID)
  186.  // and that is used as the key -- the key is kept unique (i.e., duplicate
  187.  // .empID values are not allowed).  In case of a duplicate (likely given
  188.  // the SSN generation technque), the changes made to the database are
  189.  // backed out by BULLET.  Another insert is made to cover the count requested.
  190.  
  191.  if (sameSequence)
  192.     srand(1);
  193.  else
  194.     srand((unsigned)time(0));
  195.  
  196.  sprintf(putStr,"Inserting %d recs/keys... ",recs2add);
  197.  PutMsg(putStr);
  198.  time(&startTime);
  199.  
  200.  AP.func = INSERT_XB;
  201.  AP.handle = indexID;
  202.  AP.keyPtr = keyBuffer;
  203.  AP.recPtr = &EmpRec;
  204.  AP.nextPtr = NULL;
  205.  
  206.  for (i = 1; i <= recs2add; i++) {
  207.  
  208.     rndSeqVar = (rand() >> 1) * (rand() >> 2);   // 16383*8191=134193153 max
  209.     sprintf(tmpStr,"%9.9i",rndSeqVar);
  210.     strncpy(EmpRec.empID,tmpStr,9);              // update SSN
  211.  
  212.     // on an INSERT_XB, .recNo has special meaning on input and
  213.     // must be 0 (unless one of two special cases -- see docs)
  214.  
  215.     AP.recNo = 0;
  216.  
  217.     rez = BULLET(&AP);                           // AP. already setup
  218.     if (rez) {
  219.  
  220.        // Since only a single AP pack, on an error rez will be 1 (or -1)
  221.        // this because INSERT_XB is a transaction routine and its return
  222.        // code (rez) is the number of the pack that failed (1 being the first)
  223.        // -- additionally, the number is made negative to identify the error
  224.        // as originating from the data record portion of the insert --
  225.  
  226.        // negative rc means failed during data record add
  227.  
  228.        if (rez < 0) {
  229.           rez = AP.stat;
  230.           sprintf(putStr,"Failed during data portion, sequence %d.  Err: %d\n",i,rez);
  231.           PutMsg(putStr);
  232.           goto Abend;
  233.        }
  234.  
  235.        // otherwise during index key insert
  236.  
  237.        else {
  238.           rez = AP.stat;
  239.  
  240.           // The random key generated exists, and since field is SSN which is
  241.           // usually unique enough, let's just ignore this (the data record
  242.           // has automatically be removed already) and do another insert to
  243.           // cover the recs2add amount entered by the user (user=you here).
  244.  
  245.           // NOTE: EXB_KEY_EXISTS can be handled by Bullet if during the index
  246.           // create the DUPS_ALLOWED flag were specified, but that would make
  247.           // the key two bytes longer, and since SSN, for practical purposed
  248.           // should be unique (it's said it's not...), just assume this dup
  249.           // never occured.
  250.  
  251.           if (rez == EXB_KEY_EXISTS) {
  252.              rez = 0;
  253.              i--;
  254.           }
  255.           else {
  256.              sprintf(putStr,"Failed during index portion, sequence %d.  Err: %d\n",i,rez);
  257.              PutMsg(putStr);
  258.              goto Abend;
  259.           }
  260.        }
  261.     }
  262.  
  263. #if FOR_WINDOWS == 1                   // deal with message queue every now and then
  264.     if (i % Q_INS == 0) DoWinThing(0); // 0=no waiting around
  265. #endif
  266.  
  267. }
  268.  time(&endTime);
  269.  sprintf(putStr,"took %u secs.\n",(endTime - startTime));
  270.  PutMsg(putStr);
  271.  
  272.  
  273.  memset(keyBuffer,0,sizeof(keyBuffer)); // gives the \0 to the returned key
  274.  
  275.  sprintf(putStr," Accessing %d keys...     ",recs2add);
  276.  PutMsg(putStr);
  277.  if (display) PutMsg("\n");
  278.  
  279.  time(&startTime);
  280.  AP.func = FIRST_KEY_XB;
  281.  AP.handle = indexID;
  282.  AP.keyPtr = keyBuffer;
  283.  rez = BULLET(&AP);
  284.  i=0;
  285.  while (rez==0) {
  286.     i++;
  287.     if (display) {
  288.        sprintf(putStr,"%s  %9.9u\r", keyBuffer, AP.recNo);
  289.        PutMsg(putStr);
  290.     }
  291.     AP.func = NEXT_KEY_XB;
  292.     rez = BULLET(&AP);
  293.  
  294. #if FOR_WINDOWS == 1                   // deal with message queue every now and then
  295.     if (i % Q_KEY == 0) DoWinThing(0); // 0=no waiting around
  296. #endif
  297.  
  298.  }
  299.  time(&endTime);
  300.  if (display) PutMsg("\n...");
  301.  
  302.  // expected rez is EXB_END_OF_FILE
  303.  
  304.  if (rez == EXB_END_OF_FILE) rez=0;
  305.  if (rez)  {
  306.     sprintf(putStr,"Failed KEY access.  Err: %d\n",rez);
  307.     PutMsg(putStr);
  308.     goto Abend;
  309.  }
  310.  sprintf(putStr,"took %u secs. for %d keys\n",(endTime - startTime),i);
  311.  PutMsg(putStr);
  312.  
  313.  sprintf(putStr," Accessing %d keys+recs...",recs2add);
  314.  PutMsg(putStr);
  315.  if (display) PutMsg("\n");
  316.  
  317.  time(&startTime);
  318.  AP.func = GET_FIRST_XB;
  319.  AP.handle = indexID;
  320.  AP.keyPtr = keyBuffer;
  321.  AP.recPtr = &EmpRec;
  322.  rez = BULLET(&AP);
  323.  i=0;
  324.  while (rez==0) {
  325.     i++;
  326.     if (display) {
  327.        sprintf(putStr,"%s  %9.9u   %s\r", keyBuffer, AP.recNo, &EmpRec); // to first \0
  328.        PutMsg(putStr);
  329.     }
  330.     AP.func = GET_NEXT_XB;
  331.     rez = BULLET(&AP);
  332.  
  333. #if FOR_WINDOWS == 1                   // deal with message queue every now and then
  334.     if (i % Q_GET == 0) DoWinThing(0); // 0=no waiting around
  335. #endif
  336.  
  337.  }
  338.  time(&endTime);
  339.  if (display) PutMsg("\n...");
  340.  
  341.  // expected rez is EXB_END_OF_FILE
  342.  
  343.  if (rez == EXB_END_OF_FILE) rez=0;
  344.  if (rez) {
  345.     sprintf(putStr,"Failed GET access.  Err: %d\n",rez);
  346.     goto Abend;
  347.  }
  348.  sprintf(putStr,"took %u secs. for %d keys & records\n",(endTime - startTime),i);
  349.  PutMsg(putStr);
  350.  
  351.  // Fatal errors above come straight to here
  352.  Abend:
  353.  
  354.  // Close files (index files first then data (recommended but not required))
  355.  
  356.  if (indexID) {
  357.     HP.func = CLOSE_INDEX_XB;
  358.     HP.handle = indexID;
  359.     rez = BULLET(&HP);
  360.     if (rez) {
  361.        sprintf(putStr,"Failed index file close.  Err: %d\n",rez);
  362.        PutMsg(putStr);
  363.     }
  364.  }
  365.  
  366.  if (dataID) {
  367.     HP.func = CLOSE_DATA_XB;
  368.     HP.handle = dataID;
  369.     rez = BULLET(&HP);
  370.     if (rez) {
  371.        sprintf(putStr,"Failed data file close.  Err: %d\n",rez);
  372.        PutMsg(putStr);
  373.     }
  374.  }
  375.  
  376.  return rez;  // module exit
  377. }
  378.  
  379. //------------------------------------
  380. // Init field list items for data file
  381.  
  382. void BuildFieldListIns(FIELDDESCTYPE fieldList[]) {
  383.  
  384.  strcpy(fieldList[0].fieldName, "SSN");
  385.  fieldList[0].fieldType = 'C';
  386.  fieldList[0].fieldLen = 9;
  387.  fieldList[0].fieldDC = 0;
  388.  
  389.  strcpy(fieldList[1].fieldName, "LNAME");
  390.  fieldList[1].fieldType = 'C';
  391.  fieldList[1].fieldLen = 16;
  392.  fieldList[1].fieldDC = 0;
  393.  
  394.  strcpy(fieldList[2].fieldName, "FNAME");
  395.  fieldList[2].fieldType = 'C';
  396.  fieldList[2].fieldLen = 16;
  397.  fieldList[2].fieldDC = 0;
  398.  
  399.  strcpy(fieldList[3].fieldName, "HIRED");
  400.  fieldList[3].fieldType = 'D';
  401.  fieldList[3].fieldLen = 8;      // date field type must be 8.0
  402.  fieldList[3].fieldDC = 0;
  403.  
  404.  strcpy(fieldList[4].fieldName, "DEPT");
  405.  fieldList[4].fieldType = 'C';
  406.  fieldList[4].fieldLen = 6;
  407.  fieldList[4].fieldDC = 0;
  408.  return;
  409. }
  410.