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

  1. /**********************************************************************
  2. **
  3. **                         BDATABAS.CPP
  4. **
  5. ** Member functions of the BDatabase class.  
  6. **
  7. **********************************************************************/
  8.  
  9. // DBF - (C) Copyright 1994 by Borland International
  10.  
  11. #include "kdbf.h"
  12. #pragma hdrstop
  13.  
  14. #ifdef __DLL__
  15.    #define EXPORT _export
  16. #else
  17.    #define EXPORT
  18. #endif
  19.  
  20. //
  21. // prototypes for utility functions
  22. //
  23. Retcode EXPORT GetOptionalParams(pCHAR szDriver, UINT16 *iFields,
  24.                                  pFLDDesc pfldDesc, pCHAR szData);
  25. Retcode EXPORT addDatabase(engdef *, BDatabase *);   
  26. void EXPORT deleteDatabase(engdef *, BDatabase *);   
  27. Retcode EXPORT addKeymap(engdef *, const char *, int, int, const int *);
  28. Retcode EXPORT getDesc(TABLEHANDLE, int&, FieldDesc far *); 
  29.  
  30. // Constructor for universal database.
  31.  
  32. BDatabase::BDatabase(BEngine *eng,
  33.                      DBIOpenMode openMode,
  34.                      DBIShareMode shareMode)
  35. {
  36.     dbdef *dob;
  37.  
  38.     try
  39.     {
  40.         dob = new dbdef;            // See INTSTRCT.H file.
  41.     }
  42.     catch (xalloc)
  43.     {
  44.         isOpen = FALSE;
  45.         strcpy(Alias, "");
  46.         strcpy(Driver, "");
  47.         strcpy(Password, "");
  48.         lastError = DBIERR_NOMEMORY;
  49.         return;
  50.     }
  51.     dob->handleCnt = 0;
  52.     dob->curList = 0;
  53.     dob->engH = eng;
  54.     dbobj = (void *)dob;
  55.  
  56.     if (!eng->isOpen)
  57.     {
  58.         isOpen = FALSE;
  59.         lastError = PXERR_ENGINENOTOPEN;
  60.         return;                        
  61.     }
  62.  
  63.     lastError = DbiOpenDatabase(NULL, NULL, openMode, shareMode,
  64.                                 NULL, 0, NULL, NULL, &hDb);
  65.     if (lastError != DBIERR_NONE)
  66.     {
  67.         isOpen = FALSE;
  68.         return;
  69.     }
  70.     isOpen = TRUE;
  71.     isLocal = TRUE;
  72.     strcpy(Alias, "");
  73.     strcpy(Driver, szPARADOX);
  74.     strcpy(Password, "");
  75.  
  76.     lastError = DbiGetNetUserName(userName);
  77.     if (lastError != DBIERR_NONE)
  78.     {
  79.         DbiCloseDatabase(&hDb);
  80.         return;
  81.     }
  82.  
  83.     lastError = addDatabase((engdef *)eng->engobj, this);
  84.     if (lastError != DBIERR_NONE)
  85.     {
  86.         DbiCloseDatabase(&hDb);
  87.         return;
  88.     }
  89. }
  90.  
  91. BDatabase::BDatabase(BEngine *eng,
  92.                      const char *BDDriver,
  93.                      const char *BDAlias,
  94.                      const char *BDPassword,
  95.                      DBIOpenMode openMode,
  96.                      DBIShareMode shareMode)
  97. {
  98.     UINT16  iLen;
  99.     dbdef   *dob = 0;
  100.  
  101.     hDb = 0;
  102.  
  103.     try
  104.     {
  105.         dob = new dbdef;            // See INTSTRCT.H file.
  106.         dob->handleCnt = 0;
  107.         dob->curList = 0;
  108.         dob->engH = eng;
  109.         dbobj = (void *)dob;
  110.  
  111.         if (!eng->isOpen)
  112.         {
  113.             lastError = PXERR_ENGINENOTOPEN;
  114.             throw lastError;
  115.         }
  116.  
  117.         // If standard database
  118.         if ((!strcmp(BDDriver, szPARADOX)) ||
  119.             (!strcmp(BDDriver, szDBASE))   ||
  120.             (!strcmp(BDDriver, szASCII)))
  121.         {
  122.             lastError = DbiOpenDatabase((pCHAR)BDAlias, "STANDARD", openMode,
  123.                                         shareMode, NULL, 0, NULL, NULL, &hDb);
  124.             isLocal = TRUE;
  125.         }
  126.         else
  127.         {
  128.             lastError = DbiOpenDatabase((pCHAR)BDAlias, (pCHAR)BDDriver,
  129.                                         openMode, shareMode,
  130.                                         (pCHAR)BDPassword, 0, NULL, NULL, &hDb);
  131.             isLocal = FALSE;
  132.         }
  133.         if (lastError != DBIERR_NONE)
  134.         {
  135.             throw lastError;
  136.         }
  137.         isOpen = TRUE;
  138.  
  139.         strcpy(Alias, BDAlias);
  140.  
  141.         if (BDDriver)
  142.         {
  143.             strcpy(Driver, BDDriver);
  144.         }
  145.         else
  146.         {
  147.             lastError = DbiGetProp((hDBIObj)hDb, dbDATABASETYPE, Driver,
  148.                                    DBIMAXNAMELEN, &iLen);
  149.             if (lastError)
  150.             {
  151.                 throw lastError;
  152.             }
  153.  
  154.             if (!strcmp(Driver, "STANDARD"))
  155.             {
  156.                 strcpy(Driver, szPARADOX);
  157.             }
  158.         }
  159.  
  160.         if (BDPassword)
  161.         {
  162.             strcpy(Password, BDPassword);
  163.         }
  164.  
  165.         lastError = DbiGetNetUserName(userName);
  166.         if (lastError != DBIERR_NONE)
  167.         {
  168.             throw lastError;
  169.         }
  170.  
  171.         lastError = addDatabase((engdef *)eng->engobj, this);
  172.     }
  173.     catch(xalloc)
  174.     {
  175.         if (hDb)
  176.         {
  177.             DbiCloseDatabase(&hDb);
  178.         }
  179.  
  180.         isOpen = FALSE;
  181.         strcpy(Alias, "");
  182.         strcpy(Driver, "");
  183.         strcpy(Password, "");
  184.         lastError = DBIERR_NOMEMORY;
  185.     }
  186.     catch(Retcode)
  187.     {
  188.         if (hDb)
  189.         {
  190.             DbiCloseDatabase(&hDb);
  191.         }
  192.  
  193.         strcpy(Alias, "");
  194.         strcpy(Driver, "");
  195.         strcpy(Password, "");
  196.         isOpen = FALSE;
  197.     }
  198. }
  199.  
  200.  
  201. // Destructor; if the database is open, close it first.
  202.  
  203. BDatabase::~BDatabase()
  204. {
  205.     if (isOpen)
  206.     {
  207.         close();
  208.     }
  209.  
  210.     dbdef *dob  = (dbdef *)dbobj;
  211.     if (dob)
  212.     {
  213.         // Reset pointers in any dependent cursor objects.
  214.         for (int i=0; i < dob->handleCnt; i++)
  215.         {
  216.             if (dob->curList[i])
  217.             {
  218.                 ((curdef *)dob->curList[i]->curobj)->dbH = 0;
  219.             }
  220.         }
  221.         if (dob->handleCnt)
  222.         {
  223.             delete [] dob->curList;
  224.         }
  225.         if (dob->engH)       // If engine is operating,
  226.         {
  227.            deleteDatabase((engdef *)        // remove from Engine's
  228.                           dob->engH->engobj,this);  // database list.
  229.         }
  230.         delete dob;
  231.     }
  232. }
  233.  
  234. // Open the universal database
  235.  
  236. Retcode BDatabase::open(DBIOpenMode openMode,
  237.                         DBIShareMode shareMode)
  238. {
  239.     if (isOpen)
  240.     {
  241.         return (lastError = PXERR_DBALREADYOPEN);
  242.     }
  243.  
  244.     dbdef *dob  = (dbdef *)dbobj;
  245.     if (!dob->engH || ! dob->engH->isOpen)
  246.     {
  247.         return (lastError = PXERR_ENGINENOTOPEN);
  248.     }
  249.  
  250.     lastError = DbiOpenDatabase(NULL, NULL, openMode, shareMode, NULL, 0,
  251.                                 NULL, NULL, &hDb);
  252.  
  253.     if (lastError != DBIERR_NONE)
  254.     {
  255.         isOpen = FALSE;
  256.         return lastError;
  257.     }
  258.  
  259.     isOpen = TRUE;
  260.     isLocal = TRUE;
  261.     strcpy(Alias, "");
  262.     strcpy(Driver, szPARADOX);
  263.     strcpy(Password, "");
  264.     lastError = DbiGetNetUserName(userName);
  265.     if (lastError != DBIERR_NONE)
  266.     {
  267.         return lastError;
  268.     }
  269.  
  270.     return (lastError = DBIERR_NONE);
  271. }
  272.  
  273. // Open a database
  274.  
  275. Retcode BDatabase::open(const char *BDDriver,
  276.                         const char *BDAlias,
  277.                         const char *BDPassword,
  278.                         DBIOpenMode openMode,
  279.                         DBIShareMode shareMode)
  280. {
  281.     if (isOpen)
  282.     {
  283.         return (lastError = PXERR_DBALREADYOPEN);
  284.     }
  285.  
  286.     dbdef *dob  = (dbdef *)dbobj;
  287.     if (!dob->engH || ! dob->engH->isOpen)
  288.     {
  289.         return (lastError = PXERR_ENGINENOTOPEN);
  290.     }
  291.  
  292.     // If standard database
  293.         if ((!strcmp(BDDriver, szPARADOX))  ||
  294.             (!strcmp(BDDriver, szDBASE))    ||
  295.             (!strcmp(BDDriver, szASCII)))
  296.     {
  297.         lastError = DbiOpenDatabase((pCHAR)BDAlias, (pCHAR)BDDriver,
  298.                                     openMode, shareMode, NULL, 0,
  299.                                     NULL, NULL, &hDb);
  300.         isLocal = TRUE;
  301.     }
  302.     else
  303.     {
  304.         lastError = DbiOpenDatabase((pCHAR)BDAlias, (pCHAR)BDDriver,
  305.                                     openMode, shareMode,
  306.                                     (pCHAR)BDPassword, 0, NULL, NULL, &hDb);
  307.         isLocal = FALSE;
  308.     }
  309.     if (lastError != DBIERR_NONE)
  310.     {
  311.         isOpen = FALSE;
  312.         return lastError;
  313.     }
  314.  
  315.     isOpen = TRUE;
  316.     strcpy(Alias, BDAlias);
  317.     strcpy(Driver, BDDriver);
  318.     strcpy(Password, BDPassword);
  319.     lastError = DbiGetNetUserName(userName);
  320.     if (lastError != DBIERR_NONE)
  321.     {
  322.         throw lastError;
  323.     }
  324.  
  325.     return (lastError = DBIERR_NONE);
  326. }
  327.  
  328. //  Close the database; close all cursors associated with the database.
  329.  
  330. Retcode BDatabase::close(void)
  331. {
  332.     int i;
  333.  
  334.     if (!isOpen)
  335.     {
  336.         return (lastError = PXERR_DBNOTOPEN);
  337.     }
  338.  
  339.     dbdef *dob = (dbdef *)dbobj;
  340.  
  341.     for (i=0; i < dob->handleCnt; i++)
  342.     {
  343.         if (dob->curList[i] && dob->curList[i]->isOpen)
  344.         {
  345.             if ((lastError = dob->curList[i]->close()) != 0)   // Close cursor.
  346.             {
  347.                 return lastError;
  348.             }
  349.         }
  350.     }
  351.  
  352.     lastError = DbiCloseDatabase(&hDb);
  353.     if (lastError == DBIERR_NONE)
  354.     {
  355.         isOpen = FALSE;
  356.     }
  357.  
  358.     if (TableList.isOpen)
  359.     {
  360.         TableList.close();
  361.     }
  362.  
  363.     return lastError;
  364. }
  365.  
  366. // See if a table exists in the database.
  367. BOOL BDatabase::tableExists(const char *tableName)
  368. {
  369.     BOOL        exists = FALSE;
  370.     char        *tblName;
  371.     TBLFullDesc tblDesc;
  372.     CHAR        remoteName[DBIMAXNAMELEN+1];
  373.  
  374.     if (!isOpen)
  375.     {
  376.         lastError = PXERR_DBNOTOPEN;
  377.         return exists;
  378.     }
  379.  
  380.     if (isLocal)
  381.     {
  382.         tblName = _fstrtok((pCHAR)tableName, ".");
  383.     }
  384.     else
  385.     {
  386.         if ((!strcmp(Driver, "ORACLE")) ||
  387.             (!strcmp(Driver, "SYBASE")))
  388.         {
  389.             strcpy(remoteName, userName);
  390.             strcat(remoteName, ".");
  391.             strcat(remoteName, tableName);
  392.         }
  393.         else
  394.         {
  395.             strcpy(remoteName, tableName);
  396.         }
  397.         tblName = (pCHAR)tableName;
  398.     }
  399.  
  400.     if (tblName == NULL)
  401.     {
  402.         lastError = DBIERR_INVALIDTABLENAME;
  403.         return FALSE;
  404.     }
  405.  
  406.     resetDBTableList();
  407.  
  408.     lastError = TableList.gotoTop();
  409.     if (lastError != DBIERR_NONE)
  410.     {
  411.         return FALSE;
  412.     }
  413.  
  414.     while (TableList.getNextRecord(tblDesc) == DBIERR_NONE)
  415.     {
  416.         if (!stricmp(tblDesc.tblBase.szName, tblName))
  417.         {
  418.             // Check if the types match
  419.             if (strcmp(tblDesc.tblBase.szType, Driver) && isLocal)
  420.             {
  421.                 // keep searching it the table is of the wrong type
  422.                 continue;
  423.             }
  424.             lastError = DBIERR_NONE;
  425.             return TRUE;
  426.         }
  427.     }
  428.  
  429.     lastError = DBIERR_NOSUCHTABLE;
  430.  
  431.     return exists;
  432. }
  433.  
  434. // Create a table based on its descriptor.
  435. Retcode BDatabase::createTable(const char *tableName,
  436.                                int numFields, const FieldDesc *fldDescs,
  437.                                ValidityDesc *valDesc, RefDesc *refDesc
  438.                                )
  439. {
  440.     CRTblDesc   crTblDesc;
  441.     pFLDDesc    pfldDesc    = 0;
  442.     pFLDDesc    pfldDescOpt = 0;
  443.     pCHAR       Data        = 0;       
  444.     UINT16      iFields     = 0;
  445.     UINT16      iOffset     = 0;// Offset in the default values buffer
  446.     CHAR        Temp[DBIMAXSCFLDLEN];         // Temporary Buffer
  447.     int         i;
  448.  
  449.     if (!isOpen)
  450.     {
  451.         return (lastError = PXERR_DBNOTOPEN);
  452.     }
  453.  
  454.     try
  455.     {
  456.         pfldDesc = new FLDDesc[numFields];
  457.  
  458.         memset(&crTblDesc, 0, sizeof(CRTblDesc)); // Clear the buffer.
  459.  
  460.         for (i=0; i < numFields; i++)
  461.         {
  462.             pfldDesc[i].iFldNum     = fldDescs[i].fldNum;
  463.             strcpy(pfldDesc[i].szName, fldDescs[i].fldName);
  464.             pfldDesc[i].iFldType    = fldDescs[i].fldType;
  465.             pfldDesc[i].iSubType    = fldDescs[i].fldSubtype;
  466.             pfldDesc[i].iUnits1     = fldDescs[i].fldLen;
  467.  
  468.             if (!strcmp(Driver, szDBASE))
  469.             {
  470.                 // dBASE float field needs a size - dBASE doesn't
  471.                 if ((fldDescs[i].fldType == fldDouble) &&
  472.                     (fldDescs[i].fldLen == 0))
  473.                 {
  474.                     pfldDesc[i].iUnits1     = 20;
  475.                 }
  476.                 if ((fldDescs[i].fldType == fldBcd))
  477.                 {
  478.                     pfldDesc[i].iUnits1     = 20;
  479.                     pfldDesc[i].iFldType    = fldDouble;
  480.                 } 
  481.                 if ((fldDescs[i].fldType == fldTime))
  482.                 {
  483.                     pfldDesc[i].iUnits1     = 20;
  484.                     pfldDesc[i].iFldType    = fldChar;
  485.                 } 
  486.                 if ((fldDescs[i].fldType == fldTimeStamp))
  487.                 {
  488.                     pfldDesc[i].iUnits1     = 40;
  489.                     pfldDesc[i].iFldType    = fldChar;
  490.                 } 
  491.             }
  492.  
  493.             pfldDesc[i].iUnits2     = 0;
  494.             pfldDesc[i].iOffset     = 0;
  495.             if (fldDescs[i].fldLen != 0)
  496.             {
  497.                 pfldDesc[i].iLen        = pfldDesc[i].iUnits1 + 1;
  498.             }
  499.             else
  500.             {
  501.                 pfldDesc[i].iLen        = 0;
  502.             }
  503.             pfldDesc[i].iNullOffset = 0;
  504.             pfldDesc[i].efldvVchk   = fldvNOCHECKS;
  505.             pfldDesc[i].efldrRights = fldrUNKNOWN;
  506.         }
  507.  
  508.         // Set the name and the type of the table
  509.         strcpy(crTblDesc.szTblName, tableName) ; // name of the table
  510.         strcpy(crTblDesc.szTblType, Driver) ; // Type of table
  511.  
  512.         // Set the field information for the table
  513.         crTblDesc.iFldCount     = numFields ;   // number of fields
  514.         crTblDesc.pfldDesc      = pfldDesc ;      // Field descriptor
  515.  
  516.         if (!strcmp(Driver, szPARADOX))
  517.         {
  518.             if (valDesc != NULL)
  519.             {
  520.                 crTblDesc.iValChkCount  = valDesc->valChkCount;
  521.                 crTblDesc.pecrValChkOp  = valDesc->cropType;
  522.                 crTblDesc.pvchkDesc     = valDesc->vchkDesc;
  523.             }
  524.             if (refDesc != NULL)
  525.             {
  526.                 crTblDesc.iRintCount    = refDesc->rintCount;
  527.                 crTblDesc.pecrRintOp    = refDesc->cropType;
  528.                 crTblDesc.printDesc     = refDesc->rintDesc;
  529.             }
  530.         }
  531.         
  532.         // Allocate enough space for the maximum number of fields
  533.         pfldDescOpt = new FLDDesc[DBIMAXSCFIELDS];
  534.         Data        = new CHAR[DBIMAXSCRECSIZE];
  535.  
  536.         // Initialize the pfldDesc variable to all zero's
  537.         memset((void*)pfldDescOpt, 0, sizeof(FLDDesc) * DBIMAXSCFIELDS);
  538.         memset((void*)Data, 0, sizeof(char) * DBIMAXSCRECSIZE);
  539.  
  540.         // Get the default values for the optional parameters
  541.         // Optional parameters are only valid for local tables
  542.         if ((!strcmp(Driver, szPARADOX)) ||
  543.             (!strcmp(Driver, szDBASE)))
  544.         {
  545.             lastError = GetOptionalParams(Driver, &iFields, pfldDescOpt, Data);
  546.             if (lastError != DBIERR_NONE)
  547.             {
  548.                 throw lastError;
  549.             }
  550.         }
  551.  
  552.         dbdef   *dob  = (dbdef *)dbobj;
  553.         BEnv    env;
  554.  
  555.         (dob->engH)->getDefaults(env);
  556.  
  557.         if (!strcmp(Driver, szPARADOX))
  558.         {
  559.             for (i = 0; i < iFields; i++)
  560.             {
  561.                 if (!strcmp(pfldDescOpt[i].szName, "LEVEL"))
  562.                 {
  563.                     strcpy(&Data[iOffset], itoa(env.tabCrtMode, Temp, 10));
  564.                 }
  565.                 // Set the maximum size of the table
  566.                 if (!strcmp(pfldDescOpt[i].szName, "BLOCK SIZE"))
  567.                 {
  568.                     strcpy(&Data[iOffset], itoa(env.tblMaxSize, Temp, 10));
  569.                 }
  570.                 // Increment to point to the next field within the
  571.                 // array of default values.
  572.                 iOffset += pfldDescOpt[i].iLen;
  573.             }
  574.         }
  575.  
  576.         iOffset = 0;
  577.  
  578.         if (!strcmp(Driver, szDBASE))
  579.         {
  580.             for (i = 0; i < iFields; i++)
  581.             {
  582.                 // Set the level of the table
  583.                 if (!strcmp(pfldDescOpt[i].szName, "LEVEL"))
  584.                 {
  585.                     strcpy(&Data[iOffset], itoa(env.tabCrtMode, Temp, 10));
  586.                 }
  587.                 // Increment to point to the next field within the
  588.                 // array of default values.
  589.                 iOffset += pfldDescOpt[i].iLen;
  590.             }
  591.         }
  592.  
  593.         if ((!strcmp(Driver, szPARADOX)) ||
  594.             (!strcmp(Driver, szDBASE)))
  595.         {
  596.             crTblDesc.iOptParams    = iFields;
  597.             crTblDesc.pfldOptParams = pfldDescOpt;
  598.             crTblDesc.pOptData      = (pBYTE)Data;
  599.         }
  600.  
  601.         // Create the table using information supplied in the Table
  602.         // Descrpitor above
  603.         lastError = DbiCreateTable(hDb, TRUE, &crTblDesc);
  604.         if (lastError)
  605.         {
  606.             throw lastError;
  607.         }
  608.  
  609.         resetDBTableList();
  610.  
  611.         delete pfldDesc;
  612.         pfldDesc = 0;                                              
  613.         delete pfldDescOpt;
  614.         pfldDescOpt = 0;
  615.         delete Data;
  616.         Data = 0;
  617.     }
  618.     catch(xalloc)
  619.     {
  620.         if (pfldDesc)
  621.         {
  622.             delete pfldDesc;
  623.         }
  624.         if (pfldDescOpt)
  625.         {
  626.             delete pfldDescOpt;
  627.         }
  628.         if (Data)
  629.         {
  630.             delete Data;
  631.         }
  632.     }
  633.     catch (Retcode)
  634.     {
  635.         if (pfldDesc)
  636.         {
  637.             delete pfldDesc;
  638.         }
  639.         if (pfldDescOpt)
  640.         {
  641.             delete pfldDescOpt;
  642.         }
  643.         if (Data)
  644.         {
  645.             delete Data;
  646.         }
  647.         return lastError;
  648.     }
  649.     return lastError;
  650. }
  651.  
  652. // Copy one table family to another.
  653.  
  654. Retcode BDatabase::copyTable(const char *srcTable, const char *destTable,
  655.                              const char *destType)
  656. {
  657.     BOOL    bOverWrite;
  658.     char    destTableType[DBIMAXNAMELEN + 1];
  659.  
  660.     if (!isOpen)
  661.     {
  662.         return (lastError = PXERR_DBNOTOPEN);
  663.     }
  664.  
  665.     bOverWrite = FALSE;
  666.  
  667.     if (destType == NULL)
  668.     {
  669.         strcpy(destTableType, Driver);
  670.     }
  671.     else
  672.     {
  673.         strcpy(destTableType, destType);
  674.     }
  675.     
  676.     lastError = DbiCopyTable(hDb, bOverWrite, (pCHAR)srcTable, destTableType,
  677.                              (pCHAR)destTable);
  678.  
  679.     if (lastError == DBIERR_NONE)
  680.     {
  681.         resetDBTableList();
  682.     }
  683.  
  684.     return lastError;
  685. }
  686.  
  687. // Append records of a table to the destination table.
  688. Retcode BDatabase::appendTable(const char *srcTable,
  689.                                const char *destTable,
  690.                                const char *destType,
  691.                                const BDatabase &db)
  692. {
  693.     BATTblDesc  srcTblDesc;
  694.     BATTblDesc  destTblDesc;
  695.  
  696.     if (!isOpen)
  697.     {
  698.         return (lastError = PXERR_DBNOTOPEN);
  699.     }
  700.  
  701.     memset((pVOID)&srcTblDesc, 0, sizeof(BATTblDesc));
  702.     memset((pVOID)&srcTblDesc, 0, sizeof(BATTblDesc));
  703.  
  704.     // Source table values
  705.     //   Database
  706.     srcTblDesc.hDb = hDb;
  707.     //   tablename
  708.     strcpy(srcTblDesc.szTblName, srcTable);
  709.     //   Table Type
  710.     strcpy(srcTblDesc.szTblType, Driver);
  711.  
  712.     // Destinarion table
  713.     //   Database
  714.     if (&db == NULL)
  715.     {
  716.         destTblDesc.hDb = hDb;
  717.     }
  718.     else
  719.     {
  720.         destTblDesc.hDb = db.hDb;
  721.     }
  722.  
  723.     //   Table Name
  724.     strcpy(destTblDesc.szTblName, destTable);
  725.  
  726.     //   Table Type
  727.     if (destType == NULL)
  728.     {
  729.         strcpy(destTblDesc.szTblType, Driver);
  730.     }
  731.     else
  732.     {
  733.         strcpy(destTblDesc.szTblType, destType);
  734.     }
  735.  
  736.     lastError = DbiBatchMove(&srcTblDesc, NULL, &destTblDesc, NULL, batAPPEND,
  737.                              NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  738.                              NULL, NULL, NULL, NULL, TRUE, TRUE,
  739.                              NULL, TRUE);
  740.  
  741.     return lastError;
  742. }
  743.  
  744. // Renames a table and its family members.
  745.  
  746. Retcode BDatabase::renameTable(const char *oldName, const char *newName)
  747. {
  748.     if (!isOpen)
  749.     {
  750.         return (lastError = PXERR_DBNOTOPEN);
  751.     }
  752.  
  753.     lastError = DbiRenameTable(hDb, (pCHAR)oldName, Driver, (pCHAR)newName);
  754.  
  755.     if (lastError == DBIERR_NONE)
  756.     {
  757.         resetDBTableList();
  758.     }
  759.  
  760.     return lastError;
  761. }
  762.  
  763. // Delete a table and its family.
  764.  
  765. Retcode BDatabase::deleteTable(const char *tableName)
  766. {
  767.     if (!isOpen)
  768.     {
  769.         return (lastError = PXERR_DBNOTOPEN);
  770.     }
  771.  
  772.     lastError = DbiDeleteTable(hDb, (pCHAR)tableName, Driver);
  773.  
  774.     if (lastError == DBIERR_NONE)
  775.     {
  776.         resetDBTableList();
  777.     }
  778.  
  779.     return lastError;
  780. }
  781.  
  782. // Encrypt a table based on a supplied password.
  783.  
  784. Retcode BDatabase::encryptTable(const char *tableName,
  785.           const char *password)
  786. {
  787.     CRTblDesc   crTblDesc;
  788.  
  789.     if (!isOpen)
  790.     {
  791.         return (lastError = PXERR_DBNOTOPEN);
  792.     }
  793.  
  794.     if (!isLocal)
  795.     {
  796.         return (lastError = DBIERR_NOTSUPPORTED);
  797.     }
  798.  
  799.     // Clear the buffer
  800.     memset(&crTblDesc, 0, sizeof(CRTblDesc));
  801.  
  802.     // name of the table
  803.     strcpy(crTblDesc.szTblName, tableName);
  804.     strcpy(crTblDesc.szTblType, Driver);
  805.     // Master password suplied for the table
  806.     crTblDesc.bProtected = TRUE;
  807.     // Password for the table
  808.     strcpy(crTblDesc.szPassword, password);
  809.  
  810.     lastError = DbiDoRestructure(hDb, 1, &crTblDesc, NULL, NULL, NULL, FALSE);
  811.     
  812.     return lastError;
  813. }
  814.  
  815. // Decrypt a table using a password.
  816.  
  817. Retcode BDatabase::decryptTable(const char *tableName)
  818. {
  819.     CRTblDesc   crTblDesc;
  820.  
  821.     if (!isOpen)
  822.     {
  823.         return (lastError = PXERR_DBNOTOPEN);
  824.     }
  825.  
  826.     if (!isLocal)
  827.     {
  828.         return (lastError = DBIERR_NOTSUPPORTED);
  829.     }
  830.     
  831.     // Clear the buffer
  832.     memset(&crTblDesc, 0, sizeof(CRTblDesc));
  833.  
  834.     // name of the table
  835.     strcpy(crTblDesc.szTblName, tableName);
  836.     strcpy(crTblDesc.szTblType, Driver) ; // Type of table
  837.  
  838.     lastError = DbiDoRestructure(hDb, 1, &crTblDesc, NULL, NULL, NULL, FALSE);
  839.  
  840.     return lastError;
  841. }
  842.  
  843. // Empty a table. (Delete all its records).
  844.  
  845. Retcode BDatabase::emptyTable(const char *tableName)
  846. {
  847.     if (!isOpen)
  848.     {
  849.         return (lastError = PXERR_DBNOTOPEN);
  850.     }
  851.  
  852.     lastError = DbiEmptyTable(hDb, NULL,(pCHAR)tableName, Driver);
  853.  
  854.     return lastError;
  855. }
  856.  
  857. // Upgrade a table from Paradox 3.5 to Paradox 4.0 format.
  858.  
  859. Retcode BDatabase::upgradeTable(const char *tableName)
  860. {
  861.     CRTblDesc   crTblDesc;
  862.     pFLDDesc    pfldDescOpt = 0;
  863.     pCHAR       Data        = 0;
  864.     UINT16      iFields     = 0;
  865.     int         i;
  866.     CHAR        Temp[DBIMAXSCFLDLEN];         // Temporary Buffer
  867.     UINT16      iOffset     = 0;// Offset in the default values buffer
  868.  
  869.     if (!isOpen)
  870.     {
  871.         return (lastError = PXERR_DBNOTOPEN);
  872.     }
  873.  
  874.     if (!isLocal)
  875.     {
  876.         return (lastError = DBIERR_NOTSUPPORTED);
  877.     }
  878.  
  879.     try
  880.     {
  881.         memset(&crTblDesc, 0, sizeof(CRTblDesc)); // Clear the buffer.
  882.  
  883.         // Set the name and the type of the table
  884.         strcpy(crTblDesc.szTblName, tableName) ; // name of the table
  885.         strcpy(crTblDesc.szTblType, Driver) ; // Type of table
  886.  
  887.         // Allocate enough space for the maximum number of fields
  888.         pfldDescOpt = new FLDDesc[DBIMAXSCFIELDS];
  889.         Data        = new CHAR[DBIMAXSCRECSIZE];
  890.  
  891.         // Initialize the pfldDesc variable to all zero's
  892.         memset((void*)pfldDescOpt, 0, sizeof(FLDDesc) * DBIMAXSCFIELDS);
  893.         memset((void*)Data, 0, sizeof(CHAR) * DBIMAXSCRECSIZE);
  894.  
  895.         // Get the default values for the optional parameters
  896.         lastError = GetOptionalParams(Driver, &iFields, pfldDescOpt, Data);
  897.         if (lastError != DBIERR_NONE)
  898.         {
  899.             throw lastError;
  900.         }
  901.  
  902.         if (!strcmp(Driver, szPARADOX))
  903.         {
  904.             for (i = 0; i < iFields; i++)
  905.             {
  906.                 if (!strcmp(pfldDescOpt[i].szName, "LEVEL"))
  907.                 {
  908.                     strcpy(&Data[iOffset], itoa(px50Fmt, Temp, 10));
  909.                 }
  910.                 // Increment to point to the next field within the
  911.                 // array of default values.
  912.                 iOffset += pfldDescOpt[i].iLen;
  913.             }
  914.         }
  915.  
  916.         iOffset = 0;
  917.  
  918.         if (!strcmp(Driver, szDBASE))
  919.         {
  920.             for (i = 0; i < iFields; i++)
  921.             {
  922.                 // Set the level of the table
  923.                 if (!strcmp(pfldDescOpt[i].szName, "LEVEL"))
  924.                 {
  925.                     strcpy(&Data[iOffset], itoa(px50Fmt, Temp, 10));
  926.                 }
  927.                 // Increment to point to the next field within the
  928.                 // array of default values.
  929.                 iOffset += pfldDescOpt[i].iLen;
  930.             }
  931.         }
  932.  
  933.         crTblDesc.iOptParams    = iFields;
  934.         crTblDesc.pfldOptParams = pfldDescOpt;
  935.         crTblDesc.pOptData      = (pBYTE)Data;
  936.         
  937.         lastError = DbiDoRestructure(hDb, 1, &crTblDesc, (pCHAR)tableName,
  938.                                      NULL, NULL, FALSE);
  939.  
  940.         delete pfldDescOpt;
  941.         pfldDescOpt = 0;
  942.         delete Data;
  943.         Data = 0;
  944.     }
  945.     catch(xalloc)
  946.     {
  947.         if (pfldDescOpt)
  948.         {
  949.             delete pfldDescOpt;
  950.         }
  951.         if (Data)
  952.         {
  953.             delete Data;
  954.         }
  955.     }
  956.     catch (Retcode)
  957.     {
  958.         if (pfldDescOpt)
  959.         {
  960.             delete pfldDescOpt;
  961.         }
  962.         if (Data)
  963.         {
  964.             delete Data;
  965.         }
  966.         return lastError;
  967.     }
  968.     
  969.     return lastError;
  970. }
  971.  
  972. Retcode BDatabase::restructureTable(CRTblDesc &tableDesc,
  973.                                     const char *tableName)
  974. {
  975.     if (!isOpen)
  976.     {
  977.         return (lastError = PXERR_DBNOTOPEN);
  978.     }
  979.  
  980.     if (!isLocal)
  981.     {
  982.         return (lastError = DBIERR_NOTSUPPORTED);
  983.     }
  984.     
  985.     lastError = DbiDoRestructure(hDb, 1, &tableDesc, (pCHAR)tableName,
  986.                                  NULL, NULL, FALSE);
  987.  
  988.     if (lastError == DBIERR_NONE)
  989.     {
  990.         resetDBTableList();
  991.     }
  992.  
  993.     return lastError;
  994. }
  995.  
  996. // Determine if a table is protected.
  997.  
  998. BOOL BDatabase::isProtected(const char *tableName)
  999. {
  1000.     BOOL        protect = FALSE;
  1001.     char        *tblName;
  1002.     TBLFullDesc  tblDesc;
  1003.  
  1004.     // For local Tables
  1005.     if (!isOpen)
  1006.     {
  1007.         lastError = PXERR_DBNOTOPEN;
  1008.         return protect;
  1009.     }
  1010.  
  1011.     // Different methodology required for local and remote tables
  1012.     if (isLocal)
  1013.     {
  1014.         tblName = _fstrtok((pCHAR)tableName, ".");
  1015.         if (tblName == NULL)
  1016.         {
  1017.             lastError = DBIERR_INVALIDTABLENAME;
  1018.             return FALSE;
  1019.         }
  1020.  
  1021.         resetDBTableList();
  1022.  
  1023.         lastError = TableList.gotoTop();
  1024.         if (lastError != DBIERR_NONE)
  1025.         {
  1026.             return FALSE;
  1027.         }
  1028.  
  1029.         while (TableList.getNextRecord(tblDesc) == DBIERR_NONE)
  1030.         {
  1031.             if (!stricmp(tblDesc.tblBase.szName, tblName))
  1032.             {
  1033.                 // Make certain file type match - needed in case a dBASE and
  1034.                 // Paradox table of the same name exist in the same directory.
  1035.                 if (stricmp(tblDesc.tblBase.szType, Driver))
  1036.                 {
  1037.                     // Keep searching if the type doesn't match
  1038.                     continue;
  1039.                 }
  1040.                 if (tblDesc.tblExt.bProtected == TRUE)
  1041.                 {
  1042.                     // Table is protected
  1043.                     lastError = DBIERR_NONE;
  1044.                     return TRUE;
  1045.                 }
  1046.                 else
  1047.                 {
  1048.                     lastError = DBIERR_NONE;
  1049.                     return FALSE;
  1050.                 }
  1051.             }
  1052.         }
  1053.  
  1054.         lastError = DBIERR_NOSUCHTABLE;
  1055.     }
  1056.     else
  1057.     {
  1058.         TABLEHANDLE tabH = 0;
  1059.  
  1060.         lastError = DbiOpenTable(hDb, (pCHAR)tableName, Driver,
  1061.                                  NULL, NULL, NULL, dbiREADONLY, dbiOPENSHARED,
  1062.                                  xltNONE, FALSE, NULL, &tabH);
  1063.         if (lastError == DBIERR_NONE)
  1064.         {
  1065.             DbiCloseCursor(&tabH);
  1066.             protect = FALSE;
  1067.             return protect;
  1068.         }
  1069.         else if (lastError == DBIERR_INVALIDPASSWORD)
  1070.         {
  1071.             lastError = DBIERR_NONE;
  1072.             protect = TRUE;
  1073.             return protect;
  1074.         }
  1075.     }
  1076.  
  1077.     return protect;
  1078. }
  1079.  
  1080. // Return the number of fields (columns) in a table.
  1081.  
  1082. int BDatabase::getFieldCount(const char *tableName)
  1083. {
  1084.     int         count = 0;
  1085.     char        *tblName;
  1086.     TBLFullDesc  tblDesc;
  1087.  
  1088.     if (!isOpen)
  1089.     {
  1090.         lastError = PXERR_DBNOTOPEN;
  1091.         return count;
  1092.     }
  1093.  
  1094.     // Different methodology required for local and remote tables
  1095.     if (isLocal)
  1096.     {
  1097.         tblName = _fstrtok((pCHAR)tableName, ".");
  1098.  
  1099.         if (tblName == NULL)
  1100.         {
  1101.             lastError = DBIERR_INVALIDTABLENAME;
  1102.             return 0;
  1103.         }
  1104.  
  1105.         resetDBTableList();
  1106.  
  1107.         lastError = TableList.gotoTop();
  1108.         if (lastError != DBIERR_NONE)
  1109.         {
  1110.             return FALSE;
  1111.         }
  1112.  
  1113.         while (TableList.getNextRecord(tblDesc) == DBIERR_NONE)
  1114.         {
  1115.             if (!stricmp(tblDesc.tblBase.szName, tblName))
  1116.             {
  1117.                 // For local tables, check if the types match
  1118.                 if ((!strcmp(tblDesc.tblBase.szType, szPARADOX)) ||
  1119.                     (!strcmp(tblDesc.tblBase.szType, szDBASE)))
  1120.                 {
  1121.                     if (stricmp(tblDesc.tblBase.szType, Driver))
  1122.                     {
  1123.                         // Keep searching if the type doesn't match
  1124.                         continue;
  1125.                     }
  1126.                 }
  1127.                 // Table is protected
  1128.                 lastError = DBIERR_NONE;
  1129.                 return tblDesc.tblExt.iFields;
  1130.             }
  1131.         }
  1132.  
  1133.         lastError = DBIERR_NOSUCHTABLE;
  1134.     }
  1135.     else
  1136.     {
  1137.         TABLEHANDLE tabH = 0;
  1138.         CURProps    curProps;
  1139.  
  1140.         lastError = DbiOpenTable(hDb, (pCHAR)tableName, Driver,
  1141.                                  NULL, NULL, NULL, dbiREADONLY, dbiOPENSHARED,
  1142.                                  xltNONE, FALSE, NULL, &tabH);
  1143.         if (lastError != DBIERR_NONE)
  1144.         {
  1145.            return 0;
  1146.         }
  1147.  
  1148.         lastError = DbiGetCursorProps(tabH, &curProps);
  1149.         if (lastError != DBIERR_NONE)
  1150.         {
  1151.            return 0;
  1152.         }
  1153.  
  1154.         count = curProps.iFields;
  1155.  
  1156.         DbiCloseCursor(&tabH);
  1157.     }
  1158.  
  1159.     return count;
  1160. }
  1161.  
  1162.  
  1163. // Given a table, return the number of fields in it and an array
  1164. // of its field descriptors (FieldDesc structures). The caller is
  1165. // responsible for deleting the free store memory allocated for
  1166. // the field descriptors (using delete [] desc, where
  1167. // desc is pointer to FieldDesc object).
  1168.  
  1169. Retcode BDatabase::getDescVector(char *tableName,
  1170.                                  int& numFields,
  1171.                                  FieldDesc *&fldDescs)
  1172. {
  1173.     char            *tblName;
  1174.     TBLFullDesc     tblDesc;
  1175.     TABLEHANDLE     tabH = 0;
  1176.  
  1177.     if (!isOpen)
  1178.     {
  1179.         lastError = PXERR_DBNOTOPEN;
  1180.         throw lastError;
  1181.     }
  1182.  
  1183.     try
  1184.     {
  1185.         // Need to handle local tables differently from remote tables
  1186.         if (isLocal)
  1187.         {
  1188.             tblName = _fstrtok((pCHAR)tableName, ".");
  1189.  
  1190.             if (tblName == NULL)
  1191.             {
  1192.                 lastError = DBIERR_INVALIDTABLENAME;
  1193.                 throw lastError;
  1194.             }
  1195.  
  1196.             resetDBTableList();
  1197.  
  1198.             lastError = TableList.gotoTop();
  1199.             if (lastError != DBIERR_NONE)
  1200.             {
  1201.                 return FALSE;
  1202.             }
  1203.  
  1204.             while (TableList.getNextRecord(tblDesc) == DBIERR_NONE)
  1205.             {
  1206.                 if (!stricmp(tblDesc.tblBase.szName, tblName))
  1207.                 {
  1208.                     // For local tables, check if the types match
  1209.                     if ((!strcmp(tblDesc.tblBase.szType, szPARADOX)) ||
  1210.                         (!strcmp(tblDesc.tblBase.szType, szDBASE)))
  1211.                     {
  1212.                         if (stricmp(tblDesc.tblBase.szType, Driver))
  1213.                         {
  1214.                             // Keep searching if the type doesn't match
  1215.                             continue;
  1216.                         }
  1217.                     }
  1218.  
  1219.                     numFields = tblDesc.tblExt.iFields;
  1220.  
  1221.                     lastError = DBIERR_NONE;
  1222.  
  1223.                     fldDescs = new FieldDesc[numFields];  // Allocate
  1224.                                                           // descriptor array.
  1225.  
  1226.                     lastError = getDesc(tableName, numFields,
  1227.                                         (FieldDesc far *)fldDescs);
  1228.                     if (lastError)
  1229.                     {
  1230.                         throw lastError;
  1231.                     }
  1232.  
  1233.                     return lastError;
  1234.                 }
  1235.             }
  1236.  
  1237.             lastError = DBIERR_NOSUCHTABLE;
  1238.             throw lastError;
  1239.         }
  1240.         else
  1241.         {
  1242.             CURProps    curProps;
  1243.  
  1244.             lastError = DbiOpenTable(hDb, (pCHAR)tableName, Driver,
  1245.                                      NULL, NULL, NULL, dbiREADONLY,
  1246.                                      dbiOPENSHARED, xltNONE, FALSE, NULL,
  1247.                                      &tabH);
  1248.             if (lastError != DBIERR_NONE)
  1249.             {
  1250.                throw lastError;
  1251.             }
  1252.  
  1253.             lastError = DbiGetCursorProps(tabH, &curProps);
  1254.             if (lastError != DBIERR_NONE)
  1255.             {
  1256.                throw lastError;
  1257.             }
  1258.  
  1259.             DbiCloseCursor(&tabH);
  1260.             tabH = 0;
  1261.             
  1262.             numFields = curProps.iFields;
  1263.  
  1264.             fldDescs = new FieldDesc[numFields];  // Allocate
  1265.                                                   // descriptor array.
  1266.             lastError = getDesc(tableName, numFields,
  1267.                                 (FieldDesc far *)fldDescs);
  1268.             if (lastError)
  1269.             {
  1270.                 throw lastError;
  1271.             }
  1272.  
  1273.             return lastError;
  1274.        }
  1275.     }
  1276.     catch(xalloc)
  1277.     {
  1278.         lastError = DBIERR_NOMEMORY;
  1279.         if (tabH)
  1280.         {
  1281.             DbiCloseCursor(&tabH);
  1282.         }
  1283.         if (fldDescs)
  1284.         {
  1285.             delete fldDescs;
  1286.         }
  1287.         return lastError;
  1288.     }
  1289.     catch(Retcode)
  1290.     {
  1291.         if (tabH)
  1292.         {
  1293.             DbiCloseCursor(&tabH);
  1294.         }
  1295.         if (fldDescs)
  1296.         {
  1297.             delete fldDescs;
  1298.         }
  1299.         return lastError;
  1300.     }
  1301. }
  1302.  
  1303. // Returns information about the indexes in a table
  1304.  
  1305. Retcode BDatabase::getIndexVector(char *tableName,
  1306.                                   int& numIndexes,
  1307.                                   IDXDesc *&idxDescs)
  1308. {
  1309.     char            *tblName;
  1310.     TBLFullDesc     tblDesc;
  1311.  
  1312.     if (!isOpen)
  1313.     {
  1314.         lastError = PXERR_DBNOTOPEN;
  1315.         throw lastError;
  1316.     }
  1317.  
  1318.     try
  1319.     {
  1320.         // Need to handle local tables differently from remote tables
  1321.         if (isLocal)
  1322.         {
  1323.             tblName = _fstrtok((pCHAR)tableName, ".");
  1324.  
  1325.             if (tblName == NULL)
  1326.             {
  1327.                 lastError = DBIERR_INVALIDTABLENAME;
  1328.                 throw lastError;
  1329.             }
  1330.  
  1331.             resetDBTableList();
  1332.  
  1333.             lastError = TableList.gotoTop();
  1334.             if (lastError != DBIERR_NONE)
  1335.             {
  1336.                 return FALSE;
  1337.             }
  1338.  
  1339.             while (TableList.getNextRecord(tblDesc) == DBIERR_NONE)
  1340.             {
  1341.                 if (!stricmp(tblDesc.tblBase.szName, tblName))
  1342.                 {
  1343.                     if (stricmp(tblDesc.tblBase.szType, Driver))
  1344.                     {
  1345.                         // Keep searching if the type doesn't match
  1346.                         continue;
  1347.                     }
  1348.  
  1349.                     numIndexes = tblDesc.tblExt.iIndexes;
  1350.  
  1351.                     lastError = DBIERR_NONE;
  1352.  
  1353.                     idxDescs = new IDXDesc[numIndexes]; // Allocate descriptor
  1354.                                                         //array.
  1355.  
  1356.                     getIndexDesc(tableName, numIndexes,
  1357.                                  (IDXDesc far *)idxDescs);
  1358.                                  
  1359.                     return lastError;
  1360.                 }
  1361.             }
  1362.  
  1363.             lastError = DBIERR_NOSUCHTABLE;
  1364.             throw lastError;
  1365.         }
  1366.         else
  1367.         {
  1368.             TABLEHANDLE tabH = 0;
  1369.             CURProps    curProps;
  1370.  
  1371.             lastError = DbiOpenTable(hDb, (pCHAR)tableName, Driver,
  1372.                                      NULL, NULL, NULL, dbiREADONLY,
  1373.                                      dbiOPENSHARED, xltNONE, FALSE, NULL,
  1374.                                      &tabH);
  1375.             if (lastError != DBIERR_NONE)
  1376.             {
  1377.                throw lastError;
  1378.             }
  1379.  
  1380.             lastError = DbiGetCursorProps(tabH, &curProps);
  1381.             if (lastError != DBIERR_NONE)
  1382.             {
  1383.                throw lastError;
  1384.             }
  1385.  
  1386.             DbiCloseCursor(&tabH);
  1387.             tabH = 0;
  1388.  
  1389.             numIndexes = curProps.iIndexes;
  1390.  
  1391.             idxDescs = new IDXDesc[numIndexes];  // Allocate
  1392.                                                  // descriptor array.
  1393.  
  1394.             getIndexDesc(tableName, numIndexes,
  1395.                          (IDXDesc far *)idxDescs);
  1396.             return lastError;
  1397.         }
  1398.    }
  1399.     catch(xalloc)
  1400.     {
  1401.         lastError = DBIERR_NOMEMORY;
  1402.         if (idxDescs)
  1403.         {
  1404.             delete idxDescs;
  1405.         }
  1406.         return lastError;
  1407.     }
  1408.     catch(Retcode)
  1409.     {
  1410.         if (idxDescs)
  1411.         {
  1412.             delete idxDescs;
  1413.         }
  1414.         return lastError;
  1415.     }
  1416. }
  1417.  
  1418. // Given an ordered list of fields, establish a virtual field
  1419. // as a composite of all the fields.
  1420.  
  1421. Retcode BDatabase::defineCompoundKey (const char *tableName,
  1422.                                       int numFields,
  1423.                                       const FIELDNUMBER *fldArray,
  1424.                                       const char *indexName,
  1425.                                       BOOL caseSen,
  1426.                                       FIELDNUMBER& indexHandle)
  1427. {
  1428.     IDXDesc idxDesc;
  1429.     int i;
  1430.  
  1431.     if (!isOpen)
  1432.     {
  1433.         return (lastError = PXERR_DBNOTOPEN);
  1434.     }
  1435.  
  1436.     // Composite indexes referenced by an index ID are only supported for
  1437.     // Paradox tables
  1438.     if (strcmp(Driver, szPARADOX))
  1439.     {
  1440.         return (lastError = DBIERR_NOTSUPPORTED);
  1441.     }
  1442.  
  1443.     memset(&idxDesc, 0, sizeof(IDXDesc));
  1444.  
  1445.     strcpy(idxDesc.szName, indexName);
  1446.     idxDesc.bMaintained         = TRUE;
  1447.     idxDesc.iFldsInKey          = numFields;
  1448.  
  1449.     if (numFields > DBIMAXFLDSINKEY)
  1450.     {
  1451.         return (lastError = DBIERR_OUTOFRANGE);
  1452.     }
  1453.     for (i = 0; i < numFields; i++)
  1454.     {
  1455.         idxDesc.aiKeyFld[i]     = fldArray[i];
  1456.     }
  1457.     idxDesc.bCaseInsensitive    = !caseSen;
  1458.  
  1459.     lastError = getIndexId(tableName, fldArray, indexHandle);
  1460.  
  1461.     // Check if the index exists
  1462.     if (lastError != DBIERR_NOSUCHINDEX)
  1463.     {
  1464.         return lastError;
  1465.     }                           
  1466.  
  1467.     lastError = DbiAddIndex(hDb, NULL, (pCHAR)tableName,
  1468.                             Driver, &idxDesc, NULL);
  1469.     if (lastError != DBIERR_NONE)
  1470.     {
  1471.         return lastError;
  1472.     }
  1473.  
  1474.     // Set the indexHandle to the ID of the Index
  1475.     lastError = getIndexId(tableName, indexName, indexHandle);
  1476.     if (lastError != DBIERR_NONE)
  1477.     {
  1478.         return lastError;
  1479.     }
  1480.  
  1481.     return lastError;
  1482. }
  1483.  
  1484. // Given an ordered list of fields, created a composite index
  1485.  
  1486. Retcode BDatabase::defineCompoundKey (const char *tableName,
  1487.                                       int numFields,
  1488.                                       const FIELDNUMBER *fldArray,
  1489.                                       const char *indexName,
  1490.                                       BOOL caseSen)
  1491. {
  1492.     IDXDesc     idxDesc;
  1493.     INT16       numFlds;
  1494.     FieldDesc   *fldDescs = NULL;
  1495.  
  1496.     int i;
  1497.  
  1498.     if (!isOpen)
  1499.     {
  1500.         return (lastError = PXERR_DBNOTOPEN);
  1501.     }
  1502.  
  1503.     memset(&idxDesc, 0, sizeof(IDXDesc));
  1504.  
  1505.     strcpy(idxDesc.szName, indexName);
  1506.  
  1507.     idxDesc.bMaintained         = TRUE;
  1508.     if (!strcmp(Driver, szDBASE))
  1509.     {
  1510.         idxDesc.iFldsInKey          = 1;
  1511.         idxDesc.bExpIdx             = TRUE;
  1512.         strcpy(idxDesc.szName, tableName);
  1513.         strcat(idxDesc.szName, ".MDX");
  1514.         strcpy(idxDesc.szTagName, indexName);
  1515.  
  1516.         lastError = getDescVector((pCHAR)tableName, numFlds, fldDescs);
  1517.         if (lastError != DBIERR_NONE)
  1518.         {
  1519.             return lastError;
  1520.         }
  1521.  
  1522.         strcpy(idxDesc.szKeyExp, fldDescs[(fldArray[0] - 1)].fldName);
  1523.  
  1524.         for (int i = 1; i < numFields; i++)
  1525.         {
  1526.             strncat(idxDesc.szKeyExp, " + ", DBIMAXKEYEXPLEN);
  1527.             idxDesc.szKeyExp[DBIMAXKEYEXPLEN] = 0;
  1528.             strncat(idxDesc.szKeyExp, fldDescs[(fldArray[i] - 1)].fldName,
  1529.                     DBIMAXKEYEXPLEN);
  1530.             idxDesc.szKeyExp[DBIMAXKEYEXPLEN] = 0;
  1531.         }
  1532.     }
  1533.     else
  1534.     {
  1535.         idxDesc.iFldsInKey          = numFields;
  1536.  
  1537.         for (i = 0; i < numFields; i++)
  1538.         {
  1539.             idxDesc.aiKeyFld[i]     = fldArray[i];
  1540.         }
  1541.     }
  1542.  
  1543.     if (numFields > DBIMAXFLDSINKEY)
  1544.     {
  1545.         return (lastError = DBIERR_OUTOFRANGE);
  1546.     }
  1547.     
  1548.     idxDesc.bCaseInsensitive    = !caseSen;
  1549.  
  1550.     lastError = DbiAddIndex(hDb, NULL, (pCHAR)tableName,
  1551.                             Driver, &idxDesc, NULL);
  1552.     if (lastError != DBIERR_NONE)
  1553.     {
  1554.         return lastError;
  1555.     }
  1556.  
  1557.     return lastError;
  1558. }
  1559.  
  1560. // Create a secondary index on the table.
  1561.  
  1562. Retcode BDatabase::createSIndex (const char *tableName,
  1563.           FIELDNUMBER fieldH, PXKeyCrtMode keyMode)
  1564. {
  1565.     IDXDesc     idxDesc;
  1566.     FieldDesc   *fldDescs = 0;
  1567.     INT16       numFields;
  1568.  
  1569.     if (!isOpen)
  1570.     {
  1571.         return (lastError = PXERR_DBNOTOPEN);
  1572.     }
  1573.  
  1574.     try
  1575.     {
  1576.         memset(&idxDesc, 0, sizeof(IDXDesc));
  1577.  
  1578.         lastError = getDescVector((pCHAR)tableName, numFields, fldDescs);
  1579.         if (lastError != DBIERR_NONE)
  1580.         {
  1581.             throw lastError;
  1582.         }
  1583.  
  1584.         if (fieldH > numFields)
  1585.         {
  1586.             lastError = DBIERR_OUTOFRANGE;
  1587.             throw lastError;
  1588.         }
  1589.  
  1590.         if (!strcmp(Driver, szPARADOX))
  1591.         {
  1592.             strcpy(idxDesc.szName, fldDescs[fieldH-1].fldName);
  1593.             // If a maintained index
  1594.             if (keyMode != pxSecondary)
  1595.             {
  1596.                 idxDesc.bMaintained     = TRUE;
  1597.             }
  1598.             idxDesc.iIndexId = fieldH;
  1599.         }
  1600.         else if (!strcmp(Driver, szDBASE))
  1601.         {
  1602.             if (keyMode != pxSecondary)
  1603.             {
  1604.                 strcpy(idxDesc.szName, tableName);
  1605.                 strcat(idxDesc.szName, ".MDX");
  1606.                 strcpy(idxDesc.szTagName, fldDescs[fieldH-1].fldName);
  1607.             }
  1608.             else
  1609.             {
  1610.                 strncpy(idxDesc.szName, tableName, 3);
  1611.                 idxDesc.szName[3] = 0;
  1612.                 strncat(idxDesc.szName, fldDescs[fieldH-1].fldName, 8);
  1613.                 // Make certain to NULL terminate
  1614.                 idxDesc.szName[8] = 0;
  1615.                 strcat(idxDesc.szName, ".NDX");
  1616.                 idxDesc.bMaintained = FALSE;
  1617.             }
  1618.         }
  1619.         else
  1620.         {
  1621.             strcpy(idxDesc.szName, tableName);
  1622.             strncat(idxDesc.szName, "_", DBIMAXNAMELEN);
  1623.             strncat(idxDesc.szName, fldDescs[fieldH-1].fldName, DBIMAXNAMELEN);
  1624.             idxDesc.szName[DBIMAXNAMELEN] = 0;
  1625.             idxDesc.bMaintained     = TRUE;
  1626.         }
  1627.  
  1628.         delete fldDescs;
  1629.         fldDescs = 0;
  1630.  
  1631.         idxDesc.iFldsInKey          = 1;
  1632.         idxDesc.aiKeyFld[0]         = fieldH;
  1633.         
  1634.         lastError = DbiAddIndex(hDb, NULL, (pCHAR)tableName,
  1635.                                 Driver, &idxDesc, NULL);
  1636.  
  1637.         throw lastError;
  1638.     }
  1639.     catch(xalloc)
  1640.     {
  1641.         lastError = DBIERR_NOMEMORY;
  1642.         if (fldDescs)
  1643.         {
  1644.             delete fldDescs;
  1645.         }
  1646.         return lastError;
  1647.     }
  1648.     catch(Retcode)
  1649.     {
  1650.         if (fldDescs)
  1651.         {
  1652.             delete fldDescs;
  1653.         }        
  1654.         return lastError;
  1655.     }
  1656. }
  1657.  
  1658. // Create a primary key by using the first numFields fields as the key.
  1659.  
  1660. Retcode BDatabase::createPIndex(const char *tableName, int numFields)
  1661. {
  1662.     IDXDesc     idxDesc;
  1663.     FieldDesc   *fldDescs       = 0;
  1664.     DBIKEYEXP   expression      = "";
  1665.     int         i;
  1666.     INT16       numberOfFields;
  1667.  
  1668.     if (!isOpen)
  1669.     {
  1670.         return (lastError = PXERR_DBNOTOPEN);
  1671.     }
  1672.  
  1673.     if (numFields < 1)
  1674.     {
  1675.         return (lastError = DBIERR_NOTSUPPORTED);
  1676.     }
  1677.  
  1678.     try
  1679.     {
  1680.         if (!strcmp(Driver, szPARADOX))
  1681.         {
  1682.             memset(&idxDesc, 0, sizeof(IDXDesc));
  1683.  
  1684.             idxDesc.bPrimary            = TRUE;
  1685.             idxDesc.bUnique             = TRUE;
  1686.             idxDesc.bMaintained         = TRUE;
  1687.             idxDesc.iFldsInKey          = numFields;
  1688.  
  1689.             for (i = 0; i < numFields; i++)
  1690.             {
  1691.                 idxDesc.aiKeyFld[i]     = i+1;
  1692.             }
  1693.  
  1694.             lastError = DbiAddIndex(hDb, NULL, (pCHAR)tableName,
  1695.                                     Driver, &idxDesc, NULL);
  1696.  
  1697.             throw lastError;
  1698.         }
  1699.         else if (!strcmp(Driver, szDBASE))
  1700.         {
  1701.             memset(&idxDesc, 0, sizeof(IDXDesc));
  1702.  
  1703.             lastError = getDescVector((pCHAR)tableName, numberOfFields, fldDescs);
  1704.             if (lastError != DBIERR_NONE)
  1705.             {
  1706.                 throw lastError;
  1707.             }
  1708.  
  1709.             if (numFields > numberOfFields)
  1710.             {
  1711.                 lastError = DBIERR_OUTOFRANGE;
  1712.                 throw lastError;
  1713.             }
  1714.  
  1715.             strcat(expression, fldDescs[0].fldName);
  1716.             for (int i = 1; i < numFields; i++)
  1717.             {
  1718.                 strcat(expression, " + ");
  1719.                 strcat(expression, fldDescs[i].fldName);
  1720.             }
  1721.  
  1722.             strcpy(idxDesc.szTagName, "Primary");
  1723.             strcpy(idxDesc.szKeyExp, expression);
  1724.             idxDesc.bUnique             = TRUE;
  1725.             idxDesc.bMaintained         = TRUE;
  1726.             idxDesc.bExpIdx             = TRUE;
  1727.             idxDesc.iFldsInKey          = 1;
  1728.  
  1729.             delete fldDescs;
  1730.             fldDescs = 0;
  1731.             lastError = DbiAddIndex(hDb, NULL, (pCHAR)tableName,
  1732.                                     Driver, &idxDesc, NULL);
  1733.  
  1734.             return lastError;
  1735.         }
  1736.         else if (!strcmp(Driver, szASCII))
  1737.         {
  1738.             lastError = DBIERR_NOTSUPPORTED;
  1739.             return lastError;
  1740.         }
  1741.         else
  1742.         {
  1743.             // See what happens on the server...
  1744.             memset(&idxDesc, 0, sizeof(IDXDesc));
  1745.  
  1746.             idxDesc.bPrimary            = FALSE;
  1747.             idxDesc.bUnique             = TRUE;
  1748.             idxDesc.bMaintained         = TRUE;
  1749.             idxDesc.iFldsInKey          = numFields;
  1750.  
  1751.             strcpy(idxDesc.szName, tableName);
  1752.             strncat(idxDesc.szName, "_", DBIMAXNAMELEN);
  1753.             strncat(idxDesc.szName, "Primary", DBIMAXNAMELEN);
  1754.             idxDesc.szName[DBIMAXNAMELEN] = 0;
  1755.  
  1756.             for (i = 0; i < numFields; i++)
  1757.             {
  1758.                 idxDesc.aiKeyFld[i]     = i+1;
  1759.             }
  1760.  
  1761.             lastError = DbiAddIndex(hDb, NULL, (pCHAR)tableName,
  1762.                                     Driver, &idxDesc, NULL);
  1763.  
  1764.             throw lastError;
  1765.         }
  1766.     }
  1767.     catch(xalloc)
  1768.     {
  1769.         lastError = DBIERR_NOMEMORY;
  1770.  
  1771.         if (fldDescs)
  1772.         {
  1773.             delete fldDescs;
  1774.         }
  1775.  
  1776.         return lastError;
  1777.     }
  1778.     catch(Retcode)
  1779.     {
  1780.         if (fldDescs)
  1781.         {
  1782.             delete fldDescs;
  1783.         }
  1784.         return lastError;
  1785.     }
  1786. }
  1787.  
  1788. Retcode BDatabase::createIndex(const char *tableName, IDXDesc &indexDesc)
  1789. {
  1790.     if (!isOpen)
  1791.     {
  1792.         return (lastError = PXERR_DBNOTOPEN);
  1793.     }
  1794.  
  1795.     lastError = DbiAddIndex(hDb, NULL, (pCHAR)tableName, NULL, &indexDesc,
  1796.                             NULL);
  1797.  
  1798.     return lastError;
  1799. }
  1800.  
  1801. // Delete an index on the table; the value of indexID for the
  1802. // primary key is zero.
  1803.  
  1804. Retcode BDatabase::dropIndex(const char *tableName, FIELDNUMBER indexID)
  1805. {
  1806.     char        indexName[DBIMAXNAMELEN + 1];
  1807.     char        indexTagName[DBIMAXNAMELEN + 1];
  1808.     pIDXDesc    pidxDescs = NULL;
  1809.     FieldDesc   *fldDescs = NULL;
  1810.     INT16       numFields;
  1811.     INT16       numIndexes;
  1812.  
  1813.     if (!isOpen)
  1814.     {
  1815.         return (lastError = PXERR_DBNOTOPEN);
  1816.     }
  1817.  
  1818.     try
  1819.     {
  1820.         if (!strcmp(Driver, szPARADOX))
  1821.         {
  1822.             lastError = DbiDeleteIndex(hDb, NULL, (pCHAR)tableName, Driver, NULL,
  1823.                                        NULL, indexID);
  1824.         }
  1825.         else if (!strcmp(Driver, szDBASE))
  1826.         {
  1827.             if (indexID == 0)
  1828.             {
  1829.                 strcpy(indexName, tableName);
  1830.                 strcpy(indexTagName, "Primary");
  1831.                 lastError = DbiDeleteIndex(hDb, NULL, (pCHAR)tableName, Driver,
  1832.                                            (pCHAR)indexName, (pCHAR)indexTagName, 0);
  1833.             }
  1834.             else 
  1835.             {
  1836.                 if (!tableExists(tableName))
  1837.                 {
  1838.                     return lastError;
  1839.                 }
  1840.  
  1841.                 lastError = getDescVector((pCHAR)tableName, numFields,
  1842.                                           fldDescs);
  1843.                 if (lastError != DBIERR_NONE)
  1844.                 {
  1845.                     throw lastError;
  1846.                 }
  1847.  
  1848.                 if (indexID > numFields)
  1849.                 {
  1850.                     lastError = DBIERR_OUTOFRANGE;
  1851.                     throw lastError;
  1852.                 }
  1853.  
  1854.                 lastError = getIndexVector((pCHAR)tableName, numIndexes,
  1855.                                            pidxDescs);
  1856.                 if (lastError != DBIERR_NONE)
  1857.                 {
  1858.                     throw lastError;
  1859.                 }
  1860.  
  1861.                 strncpy(indexName, tableName, 3);
  1862.                 indexName[3] = 0;
  1863.                 strncat(indexName, fldDescs[indexID-1].fldName, 8);
  1864.                 indexName[8] = 0;
  1865.                 strcat(indexName, ".NDX");
  1866.                 
  1867.                 // Check if the index exist as an .NDX index
  1868.                 if (!access(indexName, 00))
  1869.                 {
  1870.                     lastError = DbiDeleteIndex(hDb, NULL, (pCHAR)tableName,
  1871.                                                Driver, (pCHAR)indexName, NULL,
  1872.                                                0);
  1873.                 }
  1874.                 else
  1875.                 {
  1876.                     // Check if it is part of the production index
  1877.                     int i;
  1878.                     
  1879.                     for (i=0; i < numIndexes;i++)
  1880.                     {
  1881.                         if (!strcmp(pidxDescs[i].szTagName,
  1882.                                     fldDescs[indexID-1].fldName))
  1883.                         {
  1884.                             break;
  1885.                         }
  1886.                     }
  1887.  
  1888.                     // No Index Exists
  1889.                     if (i == numIndexes)
  1890.                     {
  1891.                         lastError = DBIERR_NOSUCHINDEX;
  1892.                         throw lastError;
  1893.                     }
  1894.                     
  1895.                     lastError = DbiDeleteIndex(hDb, NULL, (pCHAR)tableName,
  1896.                                                Driver,
  1897.                                                (pCHAR)pidxDescs[i].szName,
  1898.                                                (pCHAR)pidxDescs[i].szTagName, 0);
  1899.                 }
  1900.             }
  1901.         }
  1902.         else 
  1903.         {
  1904.             if (indexID == 0)
  1905.             {
  1906.                 strcpy(indexName, tableName);
  1907.                 strncat(indexName, "_", DBIMAXNAMELEN);
  1908.                 indexName[DBIMAXNAMELEN] = 0;
  1909.                 strncat(indexName, "Primary", DBIMAXNAMELEN);
  1910.                 indexName[DBIMAXNAMELEN] = 0;
  1911.  
  1912.                 lastError = DbiDeleteIndex(hDb, NULL, (pCHAR)tableName, Driver,
  1913.                                            (pCHAR)indexName, NULL, 0);
  1914.             }
  1915.             else
  1916.             {
  1917.                 lastError = getDescVector((pCHAR)tableName, numFields,
  1918.                                           fldDescs);
  1919.                 if (lastError != DBIERR_NONE)
  1920.                 {
  1921.                     throw lastError;
  1922.                 }
  1923.  
  1924.                 if (indexID > numFields)
  1925.                 {
  1926.                     lastError = DBIERR_OUTOFRANGE;
  1927.                     throw lastError;
  1928.                 }
  1929.  
  1930.                 strcpy(indexName, tableName);
  1931.                 strncat(indexName, "_", DBIMAXNAMELEN);
  1932.                 indexName[DBIMAXNAMELEN] = 0;
  1933.                 strncat(indexName, fldDescs[indexID-1].fldName, DBIMAXNAMELEN);
  1934.                 indexName[DBIMAXNAMELEN] = 0;
  1935.  
  1936.                 lastError = DbiDeleteIndex(hDb, NULL, (pCHAR)tableName, Driver,
  1937.                                            (pCHAR)indexName, NULL, 0);
  1938.             }
  1939.         }
  1940.     }
  1941.     catch(xalloc)
  1942.     {
  1943.         lastError = DBIERR_NOMEMORY;
  1944.  
  1945.         if (fldDescs)
  1946.         {
  1947.             delete fldDescs;
  1948.         }
  1949.  
  1950.         if (pidxDescs)
  1951.         {
  1952.             delete pidxDescs;
  1953.         }
  1954.  
  1955.         return lastError;
  1956.     }
  1957.     catch(Retcode one)
  1958.     {
  1959.         if (fldDescs)
  1960.         {
  1961.             delete fldDescs;
  1962.         }
  1963.  
  1964.         if (pidxDescs)
  1965.         {
  1966.             delete pidxDescs;
  1967.         }
  1968.  
  1969.         return one;
  1970.     }
  1971.  
  1972.     return lastError;
  1973. }
  1974.  
  1975. Retcode BDatabase::dropIndex(const char *tableName, const char *indexName)
  1976. {
  1977.     if (!isOpen)
  1978.     {
  1979.         return (lastError = PXERR_DBNOTOPEN);
  1980.     }
  1981.  
  1982.     if (!strcmp(Driver, szDBASE))
  1983.     {
  1984.         CHAR    idxName[DBIMAXNAMELEN + 1];
  1985.  
  1986.         strcpy(idxName, tableName);
  1987.         strncat(idxName, ".MDX", DBIMAXNAMELEN);
  1988.         idxName[DBIMAXNAMELEN] = 0;
  1989.         
  1990.         lastError = DbiDeleteIndex(hDb, NULL, (pCHAR)tableName, Driver,
  1991.                                    (pCHAR)idxName, (pCHAR)indexName, 0);
  1992.     }
  1993.     else
  1994.     {
  1995.         lastError = DbiDeleteIndex(hDb, NULL, (pCHAR)tableName, Driver,
  1996.                                    (pCHAR)indexName, NULL, 0);
  1997.     }
  1998.                                
  1999.     return lastError;
  2000. }
  2001.  
  2002. Retcode BDatabase::dropIndex(const char *tableName, const char *indexName,
  2003.                              const char *indexTagName)
  2004. {
  2005.     if (!isOpen)
  2006.     {
  2007.         return (lastError = PXERR_DBNOTOPEN);
  2008.     }
  2009.  
  2010.     lastError = DbiDeleteIndex(hDb, NULL, (pCHAR)tableName, Driver,
  2011.                                (pCHAR)indexName, (pCHAR)indexTagName, 0);
  2012.  
  2013.     return lastError;
  2014. }
  2015.  
  2016. // Get the number of primary key fields for the table.
  2017.  
  2018. int BDatabase::getNumPFields(const char *tableName)
  2019. {
  2020.     TABLEHANDLE tabH        = 0;
  2021.     pIDXDesc    pidxDesc    = 0;
  2022.     char        *fldName    = 0;
  2023.     INT16       nFields     = 0;
  2024.     INT16       i;
  2025.     INT16       numIndexes  = 0;
  2026.  
  2027.  
  2028.     if (!isOpen)                                   
  2029.     {
  2030.         lastError = PXERR_DBNOTOPEN;
  2031.         return 0;
  2032.     }
  2033.  
  2034.     try
  2035.     {
  2036.         lastError = getIndexVector((pCHAR)tableName, numIndexes, pidxDesc);
  2037.         if (lastError != DBIERR_NONE)
  2038.         {
  2039.             throw lastError;
  2040.         }
  2041.  
  2042.         if (!strcmp(Driver, szPARADOX))
  2043.         {
  2044.             for (i = 0; i < numIndexes; i++)
  2045.             {
  2046.                 if (pidxDesc[i].iIndexId == 0)
  2047.                 {
  2048.                     nFields = pidxDesc[i].iFldsInKey;
  2049.                     break;
  2050.                 }
  2051.             }
  2052.             
  2053.             if (i == numIndexes)
  2054.             {
  2055.                 lastError = DBIERR_NOSUCHINDEX;
  2056.                 throw lastError;
  2057.             }
  2058.  
  2059.             delete pidxDesc;
  2060.             pidxDesc = 0;
  2061.             
  2062.             return nFields;
  2063.         }
  2064.         else if (!strcmp(Driver, szDBASE))
  2065.         {
  2066.             // Search for the "Primary" index.
  2067.             for (i = 0; i < numIndexes; i++)
  2068.             {
  2069.                 if (!strcmp(pidxDesc[i].szTagName, "Primary"))
  2070.                 {
  2071.                     break;
  2072.                 }
  2073.             }
  2074.  
  2075.             if (i == numIndexes)
  2076.             {
  2077.                 lastError = DBIERR_NOSUCHINDEX;
  2078.                 throw lastError;
  2079.             }
  2080.  
  2081.             // Count the number of fields in the expression
  2082.             fldName = strtok(pidxDesc[i].szKeyExp, "+");
  2083.             nFields++;
  2084.             while(fldName != NULL)
  2085.             {
  2086.                 fldName = strtok(NULL, "+");
  2087.                 if(fldName != NULL)
  2088.                 {
  2089.                     nFields++;
  2090.                 }
  2091.             }
  2092.  
  2093.             delete pidxDesc;
  2094.             pidxDesc = 0;
  2095.  
  2096.             return nFields;
  2097.         }
  2098.         else
  2099.         {
  2100.             char indexName[DBIMAXNAMELEN + 1];
  2101.  
  2102.             strcpy(indexName, tableName);
  2103.             strncat(indexName, "_", DBIMAXNAMELEN);
  2104.             indexName[DBIMAXNAMELEN] = 0;
  2105.             strncat(indexName, "Primary", DBIMAXNAMELEN);
  2106.             indexName[DBIMAXNAMELEN] = 0;
  2107.  
  2108.             // Search for the "Primary" index.
  2109.             for (i = 0; i < numIndexes; i++)
  2110.             {
  2111.                 if (!strcmp(pidxDesc[i].szTagName, indexName))
  2112.                 {
  2113.                     nFields = pidxDesc[i].iFldsInKey;
  2114.                     break;
  2115.                 }
  2116.             }
  2117.  
  2118.             if (i == numIndexes)
  2119.             {
  2120.                 lastError = DBIERR_NOSUCHINDEX;
  2121.                 throw lastError;
  2122.             }
  2123.  
  2124.             delete pidxDesc;
  2125.             pidxDesc = 0;
  2126.  
  2127.             return nFields;
  2128.         }    
  2129.     }
  2130.     catch(xalloc)
  2131.     {
  2132.         lastError = DBIERR_NOMEMORY;
  2133.  
  2134.         if (pidxDesc)
  2135.         {
  2136.             delete pidxDesc;
  2137.         }
  2138.  
  2139.         if (tabH)
  2140.         {
  2141.             DbiCloseCursor(&tabH);
  2142.         }
  2143.         return 0;
  2144.     }
  2145.     catch(Retcode i)
  2146.     {
  2147.         if (tabH)
  2148.         {
  2149.             DbiCloseCursor(&tabH);
  2150.         }
  2151.         if (pidxDesc)
  2152.         {
  2153.             delete pidxDesc;
  2154.         }
  2155.         return i;
  2156.     }
  2157. }
  2158.  
  2159. // Return information on a composite secondary index.
  2160.  
  2161. #pragma argsused
  2162. Retcode BDatabase::getSKeyInfo(const char *indexName,
  2163.                                char *fldName,
  2164.                                int& numFields,
  2165.                                BOOL& caseSen,
  2166.                                FIELDNUMBER *fldArray,
  2167.                                FIELDNUMBER& indexID)
  2168. {
  2169.     if (!isOpen)
  2170.     {
  2171.         return (lastError = PXERR_DBNOTOPEN);
  2172.     }
  2173.  
  2174.     lastError = DBIERR_NOTSUPPORTED;
  2175.  
  2176.     return lastError;
  2177. }
  2178.  
  2179. // Given a single field secondary index file name, return
  2180. // information about the field.
  2181.  
  2182. #pragma argsused
  2183. Retcode BDatabase::getSKeyInfo(const char *indexName,
  2184.                                char *fldName,
  2185.                                BOOL& caseSen,
  2186.                                FIELDNUMBER& indexID)
  2187. {
  2188.     if (!isOpen)
  2189.     {
  2190.         return (lastError = PXERR_DBNOTOPEN);
  2191.     }
  2192.  
  2193.     lastError = DBIERR_NOTSUPPORTED;
  2194.     return lastError;
  2195. }
  2196.  
  2197. // Acquire a file lock on the network.
  2198.  
  2199. #pragma argsused
  2200. Retcode BDatabase::lockNetFile(const char *fileName, PXLockMode lockMode)
  2201. {
  2202.     if (!isOpen)
  2203.     {
  2204.         return (lastError = PXERR_DBNOTOPEN);
  2205.     }
  2206.  
  2207.     lastError = DbiAcqPersistTableLock(hDb, (pCHAR)fileName, Driver);
  2208.  
  2209.     return lastError;
  2210. }
  2211.  
  2212. // Release a previously acquired lock on a file.
  2213.  
  2214. #pragma argsused
  2215. Retcode BDatabase::unlockNetFile(const char *fileName, PXLockMode lockMode)
  2216. {
  2217.     if (!isOpen)
  2218.     {
  2219.         return (lastError = PXERR_DBNOTOPEN);
  2220.     }
  2221.  
  2222.     lastError = DbiRelPersistTableLock(hDb, (pCHAR)fileName, Driver);
  2223.  
  2224.     return lastError;
  2225. }
  2226.  
  2227. // Write the changed record buffers associated with this database to disk.
  2228.  
  2229. Retcode BDatabase::forceWrite(void)
  2230. {
  2231.     int i;
  2232.  
  2233.     if (!isOpen)
  2234.     {
  2235.         return (lastError = PXERR_DBNOTOPEN);
  2236.     }
  2237.  
  2238.     for (i = 0; i < ((dbdef *)dbobj)->handleCnt; i++)
  2239.     {
  2240.         // For each table in the database
  2241.         DbiSaveChanges(((dbdef *)dbobj)->curList[i]->tabH);
  2242.     }
  2243.  
  2244.     return lastError;
  2245. }
  2246.  
  2247. //  Return the name of the user causing a network locking error.
  2248.  
  2249. char *BDatabase::getNetErrUser(void)
  2250. {
  2251.     dbdef *dob = (dbdef *)dbobj;
  2252.     if (! isOpen)
  2253.     {
  2254.         lastError = PXERR_DBNOTOPEN;
  2255.         return ("");
  2256.     }
  2257.  
  2258.     lastError = DbiGetErrorContext(ecUSERNAME, dob->errUser);
  2259.  
  2260.     return (dob->errUser);
  2261. }
  2262.  
  2263. Retcode BDatabase::query(const char *qryString, BCursor &answer,
  2264.                          DBIQryLang qryLang)
  2265. {
  2266.     TABLEHANDLE tabH = 0;
  2267.  
  2268.     if (!isOpen)
  2269.     {
  2270.         return (lastError = PXERR_DBNOTOPEN);
  2271.     }
  2272.  
  2273.     lastError = DbiQExecDirect(hDb, qryLang, (pCHAR)qryString, &tabH);
  2274.     if (lastError)
  2275.     {
  2276.         return lastError;
  2277.     }
  2278.  
  2279.     lastError = answer.attach(this, tabH);
  2280.  
  2281.     DbiCloseCursor(&tabH);
  2282.  
  2283.     return lastError;
  2284. }
  2285.  
  2286. const char *BDatabase::getDriver(void)
  2287. {
  2288.     if (!isOpen)
  2289.     {
  2290.         lastError = PXERR_DBNOTOPEN;
  2291.         return NULL;
  2292.     }
  2293.  
  2294.     return Driver;
  2295. }
  2296.  
  2297. Retcode BDatabase::beginTransaction(hDBIXact &tranHandle, eXILType tranType)
  2298. {
  2299.     if (!isOpen)
  2300.     {
  2301.         lastError = PXERR_DBNOTOPEN;
  2302.         return lastError;
  2303.     }
  2304.  
  2305.     lastError = DbiBeginTran(hDb, tranType, &tranHandle);
  2306.  
  2307.     return lastError;
  2308. }
  2309.  
  2310. Retcode BDatabase::endTransaction(eXEnd tranType)
  2311. {
  2312.     if (!isOpen)
  2313.     {
  2314.         lastError = PXERR_DBNOTOPEN;
  2315.         return lastError;
  2316.     }
  2317.  
  2318.     lastError = DbiEndTran(hDb, NULL, tranType);
  2319.  
  2320.     return lastError;
  2321. }
  2322.  
  2323. Retcode BDatabase::getTransactionInfo(XInfo &tranInfo)
  2324. {
  2325.     if (!isOpen)
  2326.     {
  2327.         lastError = PXERR_DBNOTOPEN;
  2328.         return lastError;
  2329.     }
  2330.  
  2331.     lastError = DbiGetTranInfo(hDb, NULL, &tranInfo);
  2332.  
  2333.     return lastError;
  2334. }
  2335.  
  2336. Retcode BDatabase::setProp(UINT32 prop, UINT32 value)
  2337. {
  2338.     if (!isOpen)
  2339.     {
  2340.         lastError = PXERR_DBNOTOPEN;
  2341.         return lastError;
  2342.     }
  2343.  
  2344.     lastError = DbiSetProp((hDBIObj)hDb, prop, value);
  2345.  
  2346.     return lastError;
  2347. }
  2348.  
  2349. Retcode BDatabase::getProp(UINT32 prop, pVOID value, UINT16 maxLen,
  2350.                            UINT16 &retLen)
  2351. {
  2352.     if (!isOpen)
  2353.     {
  2354.         lastError = PXERR_DBNOTOPEN;
  2355.         return lastError;
  2356.     }
  2357.  
  2358.     lastError = DbiGetProp((hDBIObj)hDb, prop, value, maxLen, &retLen);
  2359.  
  2360.     return lastError;
  2361. }
  2362.  
  2363. Retcode BDatabase::setDirectory(const char *Directory)
  2364. {
  2365.     if (!isOpen)
  2366.     {
  2367.         lastError = PXERR_DBNOTOPEN;
  2368.         return lastError;
  2369.     }
  2370.  
  2371.     lastError = DbiSetDirectory(hDb, (pCHAR)Directory);
  2372.  
  2373.     if (lastError == DBIERR_NONE)
  2374.     {
  2375.         resetDBTableList();
  2376.         if (lastError != DBIERR_NONE)
  2377.         {
  2378.             return lastError;
  2379.         }
  2380.     }
  2381.  
  2382.     return lastError;
  2383. }
  2384.  
  2385. // Get the current working directory
  2386.  
  2387. Retcode BDatabase::getDirectory(char *Directory)
  2388. {
  2389.     if (!isOpen)
  2390.     {
  2391.         lastError = PXERR_DBNOTOPEN;
  2392.         return lastError;
  2393.     }
  2394.  
  2395.     lastError = DbiGetDirectory(hDb, FALSE, (pCHAR)Directory);
  2396.  
  2397.     return lastError;
  2398. }
  2399.  
  2400. // Get the default directory
  2401.  
  2402. Retcode BDatabase::getDefaultDirectory(char *Directory)
  2403. {
  2404.     if (!isOpen)
  2405.     {
  2406.         lastError = PXERR_DBNOTOPEN;
  2407.         return lastError;
  2408.     }
  2409.  
  2410.     lastError = DbiGetDirectory(hDb, TRUE, (pCHAR)Directory);
  2411.  
  2412.     return lastError;
  2413. }
  2414.  
  2415. Retcode BDatabase::getIndexId(const char *tableName, const char *indexName,
  2416.                               UINT16 &indexID)
  2417. {
  2418.     TABLEHANDLE tabH = 0;
  2419.     IDXDesc     idxDesc;
  2420.  
  2421.     if (!isOpen)
  2422.     {
  2423.         lastError = PXERR_DBNOTOPEN;
  2424.         return lastError;
  2425.     }
  2426.  
  2427.     if (strcmp(Driver, szPARADOX))
  2428.     {
  2429.         lastError = DBIERR_NOTSUPPORTED;
  2430.         return lastError;
  2431.     }
  2432.  
  2433.     lastError = DbiOpenIndexList(hDb, (pCHAR)tableName, Driver, &tabH);
  2434.     if (lastError != DBIERR_NONE)
  2435.     {
  2436.         throw lastError;
  2437.     }
  2438.  
  2439.     while (DbiGetNextRecord(tabH, dbiNOLOCK, (pBYTE)&idxDesc, NULL)
  2440.            == DBIERR_NONE)
  2441.     {
  2442.         if (!strcmp(idxDesc.szName, indexName))
  2443.         {
  2444.             indexID = idxDesc.iIndexId;
  2445.             break;            
  2446.         }
  2447.     }
  2448.  
  2449.     if (tabH)
  2450.     {
  2451.         DbiCloseCursor(&tabH);
  2452.     }
  2453.  
  2454.     return lastError;
  2455. }
  2456.  
  2457. Retcode BDatabase::getIndexId(const char *tableName,
  2458.                               const FIELDNUMBER *fldArray, UINT16 &indexID)
  2459. {
  2460.     TABLEHANDLE tabH = 0;
  2461.     IDXDesc     idxDesc;
  2462.  
  2463.     if (!isOpen)
  2464.     {
  2465.         lastError = PXERR_DBNOTOPEN;
  2466.         return lastError;
  2467.     }
  2468.  
  2469.     if (strcmp(Driver, szPARADOX))
  2470.     {
  2471.         lastError = DBIERR_NOTSUPPORTED;
  2472.         return lastError;
  2473.     }
  2474.  
  2475.     lastError = DbiOpenIndexList(hDb, (pCHAR)tableName, Driver, &tabH);
  2476.     if (lastError != DBIERR_NONE)
  2477.     {
  2478.         throw lastError;
  2479.     }
  2480.  
  2481.     while (DbiGetNextRecord(tabH, dbiNOLOCK, (pBYTE)&idxDesc, NULL)
  2482.            == DBIERR_NONE)
  2483.     {
  2484.         for (int i = 0; i < idxDesc.iFldsInKey; i++)
  2485.         {
  2486.             if (idxDesc.aiKeyFld[i] != fldArray[i])
  2487.             {
  2488.                 lastError = DBIERR_NOSUCHINDEX;
  2489.                 indexID = 0;
  2490.                 break;
  2491.             }
  2492.             lastError = DBIERR_NONE;
  2493.             indexID = idxDesc.iIndexId;
  2494.             break;
  2495.         }
  2496.     }
  2497.  
  2498.     if (tabH)
  2499.     {
  2500.         DbiCloseCursor(&tabH);
  2501.     }
  2502.  
  2503.     return lastError;
  2504. }
  2505.  
  2506. DATABASEHANDLE BDatabase::getHandle(void)
  2507. {
  2508.     if (!isOpen)
  2509.     {
  2510.         lastError = PXERR_DBNOTOPEN;
  2511.         return 0;
  2512.     }
  2513.  
  2514.     lastError = DBIERR_NONE;
  2515.  
  2516.     return hDb;
  2517. }
  2518.  
  2519. Retcode BDatabase::packTable(const char *tableName, BOOL regenIndexes)
  2520. {
  2521.     if (!isOpen)
  2522.     {
  2523.         lastError = PXERR_DBNOTOPEN;
  2524.         return 0;
  2525.     }
  2526.  
  2527.     lastError = DbiPackTable(hDb, NULL, (char *)tableName, szDBASE, regenIndexes);
  2528.  
  2529.     return lastError;
  2530. }
  2531.  
  2532. Retcode BDatabase::getDesc(const char *tableName, int& numFields,
  2533.                            FieldDesc far *fldDescs)
  2534. {
  2535.     FLDDesc     fldDesc;
  2536.     UINT16      fldNum;
  2537.     TABLEHANDLE tabH    = 0;
  2538.  
  2539.     lastError = DbiOpenFieldList(hDb, (pCHAR)tableName, Driver, FALSE,
  2540.                                  &tabH);
  2541.     if (lastError != DBIERR_NONE)
  2542.     {
  2543.         throw lastError;
  2544.     }
  2545.  
  2546.     for (fldNum = 0; fldNum < numFields; fldNum++)
  2547.     {
  2548.         lastError = DbiGetNextRecord(tabH, dbiNOLOCK,
  2549.                                      (pBYTE)&fldDesc, NULL);
  2550.         if (lastError != DBIERR_NONE)
  2551.         {
  2552.             throw lastError;
  2553.         }
  2554.  
  2555.         fldDescs[fldNum].fldNum      = fldDesc.iFldNum;
  2556.         strcpy(fldDescs[fldNum].fldName, fldDesc.szName);
  2557.         fldDescs[fldNum].fldType     =
  2558.                                   (PXFieldType)fldDesc.iFldType;
  2559.         fldDescs[fldNum].fldSubtype  =
  2560.                                (PXFieldSubtype)fldDesc.iSubType;
  2561.  
  2562.         // Remove space for trailing null terminator - to make compatible
  2563.         //   with DBF
  2564.         if (fldZSTRING == fldDescs[fldNum].fldType ||
  2565.             (fldBLOB == fldDescs[fldNum].fldType &&
  2566.              fldstMemo == fldDescs[fldNum].fldSubtype))
  2567.         {
  2568.             if (fldDesc.iLen > 1)
  2569.             {
  2570.                 --fldDesc.iLen;
  2571.             }
  2572.         }
  2573.         fldDescs[fldNum].fldLen      = fldDesc.iLen;
  2574.     }
  2575.  
  2576.     if (tabH)
  2577.     {
  2578.         DbiCloseCursor(&tabH);
  2579.     }
  2580.  
  2581.     return lastError;
  2582. }
  2583.  
  2584. Retcode BDatabase::getIndexDesc(const char *tableName, int& numIndexes,
  2585.                                 IDXDesc far *idxDescs)
  2586. {
  2587.     UINT16      idxNum;
  2588.     TABLEHANDLE tabH    = 0;
  2589.  
  2590.     lastError = DbiOpenIndexList(hDb, (pCHAR)tableName, Driver, &tabH);
  2591.     if (lastError != DBIERR_NONE)
  2592.     {
  2593.         throw lastError;
  2594.     }
  2595.  
  2596.     for (idxNum = 0; idxNum < numIndexes; idxNum++)
  2597.     {
  2598.         lastError = DbiGetNextRecord(tabH, dbiNOLOCK,
  2599.                                      (pBYTE)&(idxDescs[idxNum]), NULL);
  2600.         if (lastError != DBIERR_NONE)
  2601.         {
  2602.             throw lastError;
  2603.         }
  2604.     }
  2605.  
  2606.     if (tabH)
  2607.     {
  2608.         DbiCloseCursor(&tabH);
  2609.     }
  2610.     
  2611.     return lastError;
  2612. }
  2613.  
  2614. Retcode BDatabase::resetDBTableList()
  2615. {
  2616.     if (TableList.isOpen)
  2617.     {
  2618.         TableList.close();
  2619.         if (lastError != DBIERR_NONE)
  2620.         {
  2621.             return lastError;
  2622.         }
  2623.     }
  2624.  
  2625.     return openTableList(TableList, "*.*", TRUE);
  2626.  
  2627. }
  2628.  
  2629. Retcode BDatabase::openTableList(BListCursor<TBLBaseDesc> &tableList,
  2630.                                  const char *wildCard,
  2631.                                  BOOL system)
  2632. {
  2633.     TABLEHANDLE tabH;
  2634.     
  2635.     if (!isOpen)
  2636.     {
  2637.         return (lastError = PXERR_ENGINENOTOPEN);
  2638.     }
  2639.  
  2640.     lastError = DbiOpenTableList(hDb, FALSE, system, (pCHAR)wildCard,
  2641.                                  &tabH);
  2642.     if (lastError != DBIERR_NONE)
  2643.     {
  2644.         return lastError;
  2645.     }
  2646.  
  2647.     lastError = tableList.attach(tabH);
  2648.  
  2649.     return lastError;
  2650. }
  2651.  
  2652. Retcode BDatabase::openTableList(BListCursor<TBLFullDesc> &tableList,
  2653.                                  const char *wildCard,
  2654.                                  BOOL system)
  2655. {
  2656.     TABLEHANDLE tabH;
  2657.     
  2658.     if (!isOpen)
  2659.     {
  2660.         return (lastError = PXERR_ENGINENOTOPEN);
  2661.     }
  2662.  
  2663.     lastError = DbiOpenTableList(hDb, TRUE, system, (pCHAR)wildCard,
  2664.                                  &tabH);
  2665.     if (lastError != DBIERR_NONE)
  2666.     {
  2667.         return lastError;
  2668.     }
  2669.  
  2670.     lastError = tableList.attach(tabH);
  2671.  
  2672.     return lastError;
  2673. }
  2674.  
  2675. Retcode BDatabase::openFileList(BListCursor<FILEDesc> &fileList,
  2676.                                 const char *wildCard)
  2677. {
  2678.     TABLEHANDLE tabH;
  2679.     
  2680.     if (!isOpen)
  2681.     {
  2682.         return (lastError = PXERR_ENGINENOTOPEN);
  2683.     }
  2684.  
  2685.     lastError = DbiOpenFileList(hDb, (pCHAR)wildCard, &tabH);
  2686.     if (lastError != DBIERR_NONE)
  2687.     {
  2688.         return lastError;
  2689.     }
  2690.  
  2691.     lastError = fileList.attach(tabH);
  2692.  
  2693.     return lastError;
  2694. }
  2695.  
  2696. Retcode BDatabase::openIndexList(BListCursor<IDXDesc> &indexList,
  2697.                                  const char *tableName,
  2698.                                  const char *tableType)
  2699. {
  2700.     TABLEHANDLE tabH;
  2701.     
  2702.     if (!isOpen)
  2703.     {
  2704.         return (lastError = PXERR_ENGINENOTOPEN);
  2705.     }
  2706.  
  2707.     lastError = DbiOpenIndexList(hDb, (pCHAR)tableName, (pCHAR)tableType,
  2708.                                  &tabH);
  2709.     if (lastError != DBIERR_NONE)
  2710.     {
  2711.         return lastError;
  2712.     }
  2713.  
  2714.     lastError = indexList.attach(tabH);
  2715.  
  2716.     return lastError;
  2717. }
  2718.  
  2719. Retcode BDatabase::openFieldList(BListCursor<FLDDesc> &fieldList,
  2720.                                  const char *tableName,
  2721.                                  const char *tableType, BOOL physicalTypes)
  2722. {
  2723.     TABLEHANDLE tabH;
  2724.  
  2725.     if (!isOpen)
  2726.     {
  2727.         return (lastError = PXERR_ENGINENOTOPEN);
  2728.     }
  2729.  
  2730.     lastError = DbiOpenFieldList(hDb, (pCHAR)tableName, (pCHAR)tableType,
  2731.                                  physicalTypes, &tabH);
  2732.     if (lastError != DBIERR_NONE)
  2733.     {
  2734.         return lastError;
  2735.     }
  2736.  
  2737.     lastError = fieldList.attach(tabH);
  2738.  
  2739.     return lastError;
  2740. }
  2741.  
  2742. Retcode BDatabase::openFamilyList(BListCursor<FMLDesc> &familyList,
  2743.                                   const char *tableName,
  2744.                                   const char *tableType)
  2745. {
  2746.     TABLEHANDLE tabH;
  2747.  
  2748.     if (!isOpen)
  2749.     {
  2750.         return (lastError = PXERR_ENGINENOTOPEN);
  2751.     }
  2752.  
  2753.     lastError = DbiOpenFamilyList(hDb, (pCHAR)tableName, (pCHAR)tableType,
  2754.                                   &tabH);
  2755.     if (lastError != DBIERR_NONE)
  2756.     {
  2757.         return lastError;
  2758.     }
  2759.  
  2760.     lastError = familyList.attach(tabH);
  2761.  
  2762.     return lastError;
  2763. }
  2764.  
  2765. Retcode BDatabase::openVchkList(BListCursor<VCHKDesc> &vchkList,
  2766.                                 const char *tableName,
  2767.                                 const char *tableType)
  2768. {
  2769.     TABLEHANDLE tabH;
  2770.     
  2771.     if (!isOpen)
  2772.     {
  2773.         return (lastError = PXERR_ENGINENOTOPEN);
  2774.     }
  2775.  
  2776.     lastError = DbiOpenVchkList(hDb, (pCHAR)tableName, (pCHAR)tableType,
  2777.                                 &tabH);
  2778.     if (lastError != DBIERR_NONE)
  2779.     {
  2780.         return lastError;
  2781.     }
  2782.  
  2783.     lastError = vchkList.attach(tabH);
  2784.  
  2785.     return lastError;
  2786. }
  2787.  
  2788. Retcode BDatabase::openRintList(BListCursor<RINTDesc> &rintList,
  2789.                                 const char *tableName,
  2790.                                 const char *tableType)
  2791. {
  2792.     TABLEHANDLE tabH;
  2793.     
  2794.     if (!isOpen)
  2795.     {
  2796.         return (lastError = PXERR_ENGINENOTOPEN);
  2797.     }
  2798.  
  2799.     lastError = DbiOpenRintList(hDb, (pCHAR)tableName, (pCHAR)tableType,
  2800.                                 &tabH);
  2801.     if (lastError != DBIERR_NONE)
  2802.     {
  2803.         return lastError;
  2804.     }
  2805.  
  2806.     lastError = rintList.attach(tabH);
  2807.  
  2808.     return lastError;
  2809. }
  2810.  
  2811. Retcode BDatabase::openSecurityList(BListCursor<SECDesc> &securityList,
  2812.                                     const char *tableName,
  2813.                                     const char *tableType)
  2814. {
  2815.     TABLEHANDLE tabH;
  2816.     
  2817.     if (!isOpen)
  2818.     {
  2819.         return (lastError = PXERR_ENGINENOTOPEN);
  2820.     }
  2821.  
  2822.     lastError = DbiOpenSecurityList(hDb, (pCHAR)tableName, (pCHAR)tableType,
  2823.                                     &tabH);
  2824.     if (lastError != DBIERR_NONE)
  2825.     {
  2826.         return lastError;
  2827.     }
  2828.  
  2829.     lastError = securityList.attach(tabH);
  2830.  
  2831.     return lastError;
  2832. }
  2833.  
  2834. // Redefine pure virtuals from the BDbObject class.
  2835.  
  2836. char * BDatabase::nameOf() const
  2837. {
  2838.     return ("BDatabase");
  2839. }
  2840.  
  2841. void BDatabase::printOn( ostream& os)
  2842. {
  2843.     os << nameOf() << " { DB Name = " << Alias << " Driver = " << Driver
  2844.        << "Open Status = " << (int) isOpen << " }\n";
  2845. }
  2846.  
  2847. // The following two routines are used to maintain a list of databases for
  2848. // the Paradox Engine. The Database Framework does not assume the presense
  2849. // of any Class library (not even Borland's container library Classlib).
  2850. // Consequently, no List class is used.
  2851.  
  2852. Retcode addDatabase(engdef *eng, BDatabase *db)
  2853. {
  2854.     // Add this database object to the Database vector in the Paradox Engine.
  2855.  
  2856.     int i;
  2857.     BDatabase **newvec;
  2858.     for (i = 0; i < eng->handleCnt; i++)
  2859.     {
  2860.         if (!eng->dbList[i])  // Determine an empty slot.
  2861.         {
  2862.             eng->dbList[i] = db;
  2863.             return DBIERR_NONE;
  2864.         }
  2865.     }
  2866.     try
  2867.     {
  2868.         // Four more handles.
  2869.         newvec = new BDatabase *[eng->handleCnt+4];
  2870.     }
  2871.     catch(xalloc)
  2872.     {
  2873.         return DBIERR_NOMEMORY;
  2874.     }
  2875.     
  2876.     for (i = 0; i < eng->handleCnt; i++)
  2877.     {
  2878.         newvec[i] = eng->dbList[i];
  2879.     }
  2880.     newvec[i++] = db;
  2881.     newvec[i] = newvec[i+1] = newvec[i+2] = 0;
  2882.     if (eng->handleCnt)
  2883.     {
  2884.         delete [] eng->dbList;                             // Delete old vector.
  2885.     }
  2886.     eng->handleCnt += 4;
  2887.     eng->dbList = newvec;
  2888.  
  2889.     return DBIERR_NONE;
  2890. }
  2891.  
  2892. void deleteDatabase(engdef *eng, BDatabase *db)
  2893. {
  2894.   // Invoke when a Database object's destructor is called.
  2895.  
  2896.     for (int i = 0; i < eng->handleCnt; i++)
  2897.     {
  2898.         if (eng->dbList[i] == db)
  2899.         {
  2900.             eng->dbList[i] = 0;
  2901.             return;
  2902.         }
  2903.     }
  2904. }
  2905.  
  2906. // Add key map defined by an application to the Paradox Engine
  2907. // object; the key map results in a compound index's index
  2908. // handle that is valid only within this instance of the Engine.
  2909. // Paradox Engine semantics require the key map definition for
  2910. // every session. This information is required for some of the
  2911. // search functions provided in BCursor class.
  2912.  
  2913. Retcode addKeymap(engdef *eng, const char *tableName, int numFields,
  2914.           int indexHandle, const int *fldArray)
  2915. {
  2916.     int i,j;
  2917.     keyMapdef *newmap = 0;
  2918.  
  2919.     // See if an entry already exists.
  2920.  
  2921.     try
  2922.     {
  2923.         for (i = 0; i < eng->compIdxCnt; i++)
  2924.         {
  2925.             if (eng->keymap[i].indexId == indexHandle &&
  2926.                 eng->keymap[i].keyCnt  == numFields   &&
  2927.                 ! strcmp(eng->keymap[i].tableName, tableName))
  2928.             {
  2929.                 break;
  2930.             }
  2931.         }
  2932.         if (i == eng->compIdxCnt)              // Add a new entry.
  2933.         {
  2934.             newmap = new keyMapdef[eng->compIdxCnt+1];
  2935.             for (j = 0; j < eng->compIdxCnt; j++)
  2936.             {
  2937.                 newmap[j] = eng->keymap[j];
  2938.             }
  2939.             if (eng->compIdxCnt)             // Free old structure if
  2940.             {
  2941.                 delete [] eng->keymap;          // this is not the first.
  2942.                 eng->keymap = 0;
  2943.             }
  2944.             eng->keymap = newmap;
  2945.             eng->compIdxCnt += 1;
  2946.         }
  2947.         else
  2948.         {
  2949.             // Delete allocated memory in old structure for the index.
  2950.  
  2951.             delete eng->keymap[i].tableName;
  2952.             eng->keymap[i].tableName = 0;
  2953.             delete [] eng->keymap[i].fieldArray;
  2954.             eng->keymap[i].fieldArray = 0;
  2955.         }
  2956.  
  2957.         // Add information at index position i. The memory allocated
  2958.         // here will be freed when the engine is closed.
  2959.  
  2960.         eng->keymap[i].indexId = indexHandle;
  2961.         eng->keymap[i].keyCnt  = numFields;
  2962.         // Need to know that value is 0 on failure
  2963.         eng->keymap[i].tableName = 0;
  2964.         eng->keymap[i].tableName  = new char[strlen(tableName)+1];
  2965.         strcpy(eng->keymap[i].tableName,tableName);
  2966.         // Need to know that value is 0 on failure
  2967.         eng->keymap[i].fieldArray = 0;
  2968.         eng->keymap[i].fieldArray = new int[numFields];
  2969.         for (j = 0; j < numFields; j++)
  2970.         {
  2971.             eng->keymap[i].fieldArray[j] = fldArray[j];
  2972.         }
  2973.  
  2974.         return DBIERR_NONE;
  2975.     }
  2976.     catch(xalloc)
  2977.     {
  2978.         if (newmap)
  2979.         {
  2980.             delete newmap;
  2981.         }
  2982.  
  2983.         if (eng->keymap[i].tableName)
  2984.         {
  2985.             delete eng->keymap[i].tableName;
  2986.         }
  2987.  
  2988.         if (eng->keymap[i].fieldArray)
  2989.         {
  2990.             delete eng->keymap[i].fieldArray;
  2991.         }
  2992.  
  2993.         return DBIERR_NOMEMORY;
  2994.     }
  2995. }
  2996.  
  2997. Retcode getDesc (TABLEHANDLE tabH, int& numFields, FieldDesc far *fldDescs)
  2998. {
  2999.     pFLDDesc    pfldDesc = 0;
  3000.     Retcode     rslt;
  3001.     int         i;
  3002.  
  3003.     try
  3004.     {
  3005.         pfldDesc = new FLDDesc[numFields];
  3006.  
  3007.         rslt = DbiGetFieldDescs(tabH, pfldDesc);
  3008.         if (rslt != DBIERR_NONE)
  3009.         {
  3010.             throw rslt;
  3011.         }
  3012.  
  3013.         for (i=0; i < numFields; i++)
  3014.         {
  3015.             fldDescs[i].fldNum      = pfldDesc[i].iFldNum;
  3016.             strcpy(fldDescs[i].fldName, pfldDesc[i].szName);
  3017.             fldDescs[i].fldType     = (PXFieldType)pfldDesc[i].iFldType;
  3018.             fldDescs[i].fldSubtype  = (PXFieldSubtype)pfldDesc[i].iSubType;
  3019.  
  3020.             // Remove space for trailing null terminator - to make compatible
  3021.             //   with DBF
  3022.             if (fldZSTRING == fldDescs[ i ].fldType ||
  3023.                 (fldBLOB == fldDescs[ i ].fldType &&
  3024.                  fldstMemo == fldDescs[i].fldSubtype))
  3025.             {
  3026.                 if (pfldDesc[i].iLen > 1)
  3027.                 {
  3028.                     --pfldDesc[i].iLen;
  3029.                 }
  3030.             }
  3031.  
  3032.             fldDescs[i].fldLen      = pfldDesc[i].iLen;
  3033.         }
  3034.  
  3035.         delete pfldDesc;
  3036.         pfldDesc = 0;
  3037.  
  3038.         return DBIERR_NONE;
  3039.     }
  3040.     catch(xalloc)
  3041.     {
  3042.         if (pfldDesc)
  3043.         {
  3044.             delete pfldDesc;
  3045.         }
  3046.         return DBIERR_NOMEMORY;
  3047.     }
  3048.     catch(Retcode)
  3049.     {
  3050.         return rslt;
  3051.     }
  3052. }
  3053.  
  3054. //=====================================================================
  3055. //  Code:   GetOptionalParams(pCHAR szDriver, UINT16 *iFields,
  3056. //                            pFLDDesc pfldDesc, pCHAR szData);
  3057. //
  3058. //  Input:  szDriver    - Name of the driver
  3059. //          iFields     - Used to return the number of fields
  3060. //          pfldDesc    - Returns the descriptors of the fields.
  3061. //                          Memory for this variable must be allocated by
  3062. //                          the calling calling.
  3063. //          szData      - Contains the values of the fields. Memory for
  3064. //                          this variable must be allocated by the calling
  3065. //                          function.
  3066. //
  3067. //  Return: DBIResult - success of the function
  3068. //
  3069. //  Description:
  3070. //          This function is used to return the available optional
  3071. //          parameters when creating a table of the given type. This
  3072. //          information includes the number of optional parameters
  3073. //          (iFields), an array of field descriptors describing those
  3074. //          parameters, and the default values for the parameters.
  3075. //=====================================================================
  3076. Retcode                          
  3077. GetOptionalParams (pCHAR szDriver, UINT16 *iFields,
  3078.                    pFLDDesc pfldDesc, pCHAR szData)
  3079. {
  3080.     DBIResult   rslt;       // Return value from IDAPI functions
  3081.     TABLEHANDLE tabH = 0;   // Handle to the Cursor
  3082.     pCHAR       szNode = 0; // String which contains the name of the node
  3083.     pCFGDesc    CfgDesc = 0;// Configuration Descriptor
  3084.     CHAR        szCfgPath[DBIMAXPATHLEN + 1]; // Maximum length of the path
  3085.                             // in the configuration file.
  3086.     UINT16      iOffset = 0;
  3087.  
  3088.     try
  3089.     {
  3090.         // Set up the option to get from the Configuration File
  3091.         strcpy(szCfgPath, "\\DRIVERS\\");
  3092.         strcat(szCfgPath, szDriver);
  3093.         strcat(szCfgPath, "\\TABLE CREATE");
  3094.     
  3095.         // Open the Configuration file - returns the configuration options
  3096.         // for the current level in a schema table referenced by tabH.
  3097.         rslt = DbiOpenCfgInfoList(NULL, dbiREADONLY, cfgPersistent,
  3098.                                   szCfgPath, &tabH);
  3099.         if (rslt != DBIERR_NONE)
  3100.         {
  3101.             throw rslt;
  3102.         }
  3103.  
  3104.         // Allocate resources
  3105.         szNode = new CHAR[256];
  3106.         CfgDesc = new CFGDesc;
  3107.  
  3108.         *iFields = 0;
  3109.         // Process all nodes
  3110.         //   Get the next record in the table - contains the next option
  3111.         //   of the given level in the tree.
  3112.         while (DbiGetNextRecord(tabH, dbiNOLOCK, (pBYTE)CfgDesc, NULL)
  3113.                == DBIERR_NONE)
  3114.         {
  3115.             pfldDesc[*iFields].iFldNum = *iFields + 1;
  3116.             pfldDesc[*iFields].iFldType = CfgDesc->iDataType;
  3117.             pfldDesc[*iFields].iUnits1 = DBIMAXSCFLDLEN - 1;
  3118.             pfldDesc[*iFields].iLen = DBIMAXSCFLDLEN;
  3119.             strcpy(pfldDesc[*iFields].szName, CfgDesc->szNodeName);
  3120.             if (!strcmp(szDriver, szDBASE))
  3121.             {
  3122.                 pfldDesc[*iFields].iOffset = DBIMAXSCFLDLEN * (*iFields);
  3123.             }
  3124.  
  3125.             // Display the remaining information
  3126.             //    Display the Description of the node
  3127.             sprintf(szNode, "%s", CfgDesc->szValue);
  3128.             strcpy(&szData[iOffset], szNode);
  3129.             iOffset += pfldDesc[*iFields].iLen;
  3130.             (*iFields)++;
  3131.         }
  3132.  
  3133.         // Clean up
  3134.         delete szNode;
  3135.         szNode = 0;
  3136.         delete CfgDesc;
  3137.         CfgDesc = 0;
  3138.         
  3139.         rslt = DbiCloseCursor(&tabH);
  3140.         if (rslt != DBIERR_NONE)
  3141.         {
  3142.             throw rslt;
  3143.         }
  3144.         tabH = 0;
  3145.         
  3146.         return rslt;
  3147.     }
  3148.     catch(xalloc)
  3149.     {
  3150.         if (szNode)
  3151.         {
  3152.             delete szNode;
  3153.         }
  3154.  
  3155.         if (CfgDesc)
  3156.         {
  3157.             delete CfgDesc;
  3158.         }
  3159.  
  3160.         return rslt;
  3161.     }
  3162.     catch(Retcode)
  3163.     {
  3164.         if (szNode)
  3165.         {
  3166.             delete szNode;
  3167.         }
  3168.  
  3169.         if (CfgDesc)
  3170.         {
  3171.             delete CfgDesc;
  3172.         }
  3173.  
  3174.         return rslt;
  3175.     }
  3176. }
  3177.  
  3178. #pragma
  3179. static void makeDBInst()
  3180. {
  3181.     BListCursor<TBLBaseDesc> bListBaseTableDesc;
  3182.     BListCursor<TBLFullDesc> bListExtendedTableDesc;
  3183.     BListCursor<FILEDesc> bListFileDesc;
  3184.     BListCursor<IDXDesc> bListIndexDesc;
  3185.     BListCursor<FLDDesc> bListFieldDesc;
  3186.     BListCursor<FMLDesc> bListFamilyDesc;
  3187.     BListCursor<VCHKDesc> bListVchkDesc;
  3188.     BListCursor<RINTDesc> bListRintDesc;
  3189.     BListCursor<SECDesc> bListSecurityDesc;
  3190. }
  3191.  
  3192.