// BDE - (C) Copyright 1995 by Borland International // valcheck.c #include "snipit.h" #include // Set the length of the Cube Number field. #define CUBELEN 10 static const char szTblName[] = "personel"; static const char szTblType[] = szPARADOX; // Lookup table name. static const char szTblLookup[] = "CubeNum"; // Field descriptor used in creating the main table. static SNIPFAR FLDDesc fldDesc[] = { { // Field 1 - Full Name 1, // Field number "Full Name", // Field name fldZSTRING, // Field type fldUNKNOWN, // Field subtype 40, // Field size (1 or 0, except // BLOB or CHAR field) 0, // Decimal places ( 0 ) // computed 0, // Offset in record ( 0 ) 0, // Length in bytes ( 0 ) 0, // For Null bits ( 0 ) fldvHASCHECKS,// This field has validity checking fldrREADWRITE // Rights }, { // Field 2 - Employee Number 2, "Employee Number", fldINT16, fldUNKNOWN, 0, 0, 0, 0, 0, fldvHASCHECKS, fldrREADWRITE }, { // Field 3 - Department Number 3, "Department Number", fldINT16, fldUNKNOWN, 0, 0, 0, 0, 0, fldvHASCHECKS, fldrREADWRITE }, { // Field 4 - Building Number 4, "Building Number", fldINT16, fldUNKNOWN, 0, 0, 0, 0, 0, fldvHASCHECKS, fldrREADWRITE }, { // Field 5 - Social Security Number 5, "SS Number", fldZSTRING, fldUNKNOWN, 11, 0, 0, 0, 0, fldvHASCHECKS, fldrREADWRITE }, { // Field 6 - Cube Number 6, "Cube Number", fldZSTRING, fldUNKNOWN, CUBELEN, 0, 0, 0, 0, fldvHASCHECKS, fldrREADWRITE } }; // Array of field descriptors. // Field descriptor used to create the lookup table. static SNIPFAR FLDDesc lkfldDesc[] = { { // Field 1 - Full Name 1, // Field number "Cube Number",// Field name fldZSTRING, // Field type fldUNKNOWN, // Field subtype CUBELEN, // Field size (1 or 0, except // BLOB or CHAR field) 0, // Decimal places ( 0 ) // computed 0, // Offset in record ( 0 ) 0, // Length in bytes ( 0 ) 0, // For Null bits ( 0 ) fldvNOCHECKS, // This field has validity checking fldrREADWRITE // Rights } }; // Array of field descriptors // Validity check descriptor - Describes the validity checks. This validity // check will be added to the table when the table is created. // Note: The min val, max val, and default val validity checks are set // within the CreateValCheck function, because the validity check // needs to store data in the same format as the field. In this case // the fields are fldINT16. This requires that a memset be done to // copy the value into the validity check. static SNIPFAR VCHKDesc VchkDesc[] = { { // First field validity check - Required field. 1, // Field number this belongs to TRUE, // Is a required field FALSE, // If True, has min value FALSE, // If True, has max value FALSE, // If True, has default value { NULL }, // Min value { NULL }, // Max value { NULL }, // Default value { NULL }, // Picture string lkupNONE, // Lookup/Fill type { NULL }, // Lookup table name }, { // Second field validity check - min value - see note above. 2, FALSE, TRUE, FALSE, FALSE, {"15"}, { NULL }, { NULL }, { NULL }, lkupNONE, { NULL } }, { // Third field validity check - max value - see note above. 3, FALSE, FALSE, TRUE, FALSE, { NULL }, {"3000"}, { NULL }, { NULL }, lkupNONE, { NULL } }, { // Fourth field validity check - default value - see note // above. 4, FALSE, FALSE, FALSE, TRUE, { NULL }, { NULL }, {"8"}, { NULL }, lkupNONE, { NULL } }, { // Fifth field validity check - picture of a SS number. 5, FALSE, FALSE, FALSE, FALSE, { NULL }, { NULL }, { NULL }, { "###-##-####" }, lkupNONE, { NULL } }, { // Sixth field validity check - lookup table. 6, FALSE, FALSE, FALSE, FALSE, { NULL }, { NULL }, { NULL }, { NULL }, lkupPRIVATE, "cubenum.db" } }; // Index descriptor. static SNIPFAR IDXDesc idxDesc[] = { { // Primary Index - Full Name "Employee Name", // Name 1, // Number { NULL }, // Tag name ( for dBase ) { NULL }, // Optional format ( BTREE, // HASH, etc ) TRUE, // Primary? TRUE, // Unique? FALSE, // Descending? TRUE, // Maintained? FALSE, // Subset? FALSE, // Expression index? NULL, // For QBE only 1, // Fields in key 1, // Length in bytes FALSE, // Index out of date? 0, // Key type of expression { 1 }, // Array of field numbers { 0 }, // Key expression { 0 }, // Key condition FALSE, // Case insensitive 0, // Block size in bytes 0 // Restructure number } }; // Index descriptor. This index array will be used to create the lookup table's // primary index. static SNIPFAR IDXDesc lkidxDesc[] = { { // Primary Index - Full name "Cube_Number",// Name 1, // Number { NULL }, // Tag name ( for dBase ) { NULL }, // Optional format ( BTREE, // HASH, etc ) TRUE, // Primary? TRUE, // Unique? FALSE, // Descending? TRUE, // Maintained? FALSE, // Subset? FALSE, // Expression index? NULL, // For QBE only 1, // Fields in key 1, // Length in bytes FALSE, // Index out of date? 0, // Key type of expression { 1 }, // Array of field numbers { 0 }, // Key expression { 0 }, // Key condition FALSE, // Case insensitive 0, // Block size in bytes 0 // Restructure number } }; // The number of fields in the table. static const unsigned uNumFields = sizeof(fldDesc) / sizeof (fldDesc[0]); // Number of indexes to be created when the table is created. static const unsigned uNumIndexes = sizeof(idxDesc) / sizeof(idxDesc[0]); // The number of fields in the lookup table. static const unsigned ulkNumFields = sizeof(lkfldDesc) / sizeof (lkfldDesc[0]); // Number of indexes to be created when the lookup table is created. static const UINT16 ulkNumIndexes = sizeof(lkidxDesc) / sizeof(lkidxDesc[0]); // Number of validity checks to be created. static const UINT16 uNumVchks = sizeof(VchkDesc) / sizeof(VchkDesc[0]); static DBIResult CreateVCHKTable(phDBIDb phDb); static DBIResult InitLKTable(phDBIDb phDb); static DBIResult AddRecord(hDBICur hCur, pCHAR pszName, INT16 lEmpNum, INT16 lDeptNum, INT16 lBuildNum, pCHAR pszSSNum, pCHAR pszCube); static DBIResult AddLKRecord(hDBICur hCur, pCHAR pszCube); static DBIResult FindRecord(pCHAR pszString, hDBICur hCur); static void FormatPic(pCHAR pszDest, pCHAR pszPicture, pCHAR pszData); //===================================================================== // Function: // ValCheck(); // // Description: // This function shows how validity checks are used on a Paradox // table. This example will create a table to which the validity // checks are added, as well as a lookup table which is used as // part of the validity checks. All tables are deleted at the end // of this example. // // This example places the following validity checks on the table: // Required on the "Full Name" field. // Minimum value of "15" on the "Employee Number" field. // Maximum value of "3000" on the "Department Number" field. // Default value of "8" on the "Building Number" field. // Picture on the "SS Number" field. // Lookup table for the "Cube Number" field. //===================================================================== void ValCheck (void) { DBIResult rslt; // Return value from IDAPI functions hDBIDb hDb; // Database handle hDBICur hCur; // Cursor handle CURProps TblProps; // Table properties CHAR SSNumber[12]; // SS number string used for VC pictures Screen("*** Validity Check Example ***\r\n"); BREAK_IN_DEBUGGER(); Screen(" Initializing IDAPI..."); if (InitAndConnect(&hDb) != DBIERR_NONE) { Screen("\r\n*** End of Example ***"); return; } Screen(" Setting the database directory..."); rslt = DbiSetDirectory(hDb, (pCHAR) szTblDirectory); ChkRslt(rslt, "SetDirectory"); // Create the lookup table and fill with data. if (InitLKTable(&hDb)) { CloseDbAndExit(&hDb); Screen("\r\n*** End of Example ***"); return; } // Create the table and attach the validity checks. if (CreateVCHKTable(&hDb)) { CloseDbAndExit(&hDb); Screen("\r\n*** End of Example ***"); return; } Screen(" Open the %s table...", szTblName); rslt = DbiOpenTable(hDb, (pCHAR) szTblName, (pCHAR) szTblType, NULL, NULL, 0, dbiREADWRITE, dbiOPENSHARED, xltFIELD, FALSE, NULL, &hCur); if (ChkRslt(rslt, "OpenTable") != DBIERR_NONE) { CloseDbAndExit(&hDb); Screen("\r\n*** End of Example ***"); return; } Screen(" Get the number of validity checks on the %s table...", szTblName); rslt = DbiGetCursorProps(hCur, &TblProps); ChkRslt(rslt, "GetCursorProps"); Screen(" There are %d validity checks on the table", TblProps.iValChecks); // Add a record without the required field (field #1). Screen("\r\n Adding the first record..."); // IDAPI does not format the data to match the picture. It only stores // the picture. FormatPic(SSNumber, "###-##-####", "111223333"); Screen(" Error expected - adding a record that does not have data" "\r\n in the first field (Full Name)," "\r\n which is a required field..."); AddRecord(hCur, "", 20, 2809, NULL, SSNumber, "2001"); Screen("\r\n Adding a record which satisfies the following" " validity checks:\r\n\r\n\t" " Required field for the first field - Full Name\r\n\t" " Minimum Value of 15 for the second field - Employee Number" "\r\n\t" " Maximum value of 3000 for the third field - Department Number" "\r\n\t" " Default value of 8 for the fourth field - Building Number" "\r\n\t" " Picture of ###-##-#### for the fifth field - SS Number" "\r\n\t" " Lookup table for the sixth field - Cube Number\r\n"); // We are passing in NULL to the AddRecord function so that IDAPI will // fill in the default value of 8 for the Building Number field. AddRecord(hCur, "Goliath Mager", 24, 2806, NULL, SSNumber, "2004"); // Find the newly added record so we can display it. FindRecord("Goliath Mager", hCur); Screen(" Displaying the record..."); DisplayNextRecord(hCur); Screen("\r\n Close the table..."); rslt = DbiCloseCursor(&hCur); ChkRslt(rslt, "CloseCursor"); Screen(" Delete the table..."); rslt = DbiDeleteTable(hDb, (pCHAR) szTblName, (pCHAR) szTblType); ChkRslt(rslt, "DeleteTable"); Screen(" Delete the lookup table and indexes..."); rslt = DbiDeleteTable(hDb, (pCHAR) szTblLookup, (pCHAR) szTblType); ChkRslt(rslt, "DeleteTable"); Screen(" Close the database and exit IDAPI..."); CloseDbAndExit(&hDb); Screen("\r\n*** End of Example ***"); } //===================================================================== // Function: // CreateVCHKTable(phDb); // // Input: phDb - Pointer to the database handle // // Return: Result of the table initialization // // Description: // This function will create a table with the validity // checks that are in the array called VchkDesc. //===================================================================== DBIResult CreateVCHKTable (phDBIDb phDb) { DBIResult rslt; // Value returned from IDAPI functions CRTblDesc crTblDsc; // Table descriptor BOOL bOverWrite = TRUE; // Overwrite, yes/no flag INT16 iDefVal = 8; // Default value for the "Building Number" // Field INT16 iMinVal = 15; // Min Value for the "Employee Number" // field INT16 iMaxVal = 3000; // Max value for the "Department Number" // field // Need to have actual integer values for the validity check. memcpy(&(VchkDesc[1].aMinVal), &iMinVal, sizeof(INT16)); memcpy(&(VchkDesc[2].aMaxVal), &iMaxVal, sizeof(INT16)); memcpy(&(VchkDesc[3].aDefVal), &iDefVal, sizeof(INT16)); // Initialize the table create descriptor. memset(&crTblDsc, 0, sizeof(CRTblDesc)); strcpy(crTblDsc.szTblName, szTblName); strcpy(crTblDsc.szTblType, szTblType); crTblDsc.iFldCount = uNumFields; crTblDsc.pfldDesc = fldDesc; crTblDsc.iIdxCount = uNumIndexes; crTblDsc.pidxDesc = idxDesc; crTblDsc.iValChkCount = uNumVchks; crTblDsc.pvchkDesc = VchkDesc; Screen(" Creating the %s table...", szTblName); rslt = DbiCreateTable(*phDb, bOverWrite, &crTblDsc); if (ChkRslt(rslt, "CreateTable") != DBIERR_NONE) { return rslt; } return rslt; } //===================================================================== // Function: // InitLKTable(phDb); // // Input: phDb - Pointer to the database handle // // Return: Result of the table initialization // // Description: // This function will create the lookup table that is used // by the validity checks. //===================================================================== DBIResult InitLKTable (phDBIDb phDb) { DBIResult rslt; // Value returned from IDAPI functions hDBICur hCur; // Cursor handle for the table that is // created CRTblDesc crTblDsc; // Table descriptor BOOL bOverWrite = TRUE; // Overwrite, yes/no flag // Initialize the Table Create Descriptor. memset(&crTblDsc, 0, sizeof(CRTblDesc)); strcpy(crTblDsc.szTblName, szTblLookup); strcpy(crTblDsc.szTblType, szTblType); crTblDsc.iFldCount = ulkNumFields; crTblDsc.pfldDesc = lkfldDesc; crTblDsc.iIdxCount = ulkNumIndexes; crTblDsc.pidxDesc = lkidxDesc; Screen(" Creating lookup table and indexes..."); rslt = DbiCreateTable(*phDb, bOverWrite, &crTblDsc); if (ChkRslt(rslt, "CreateTable") != DBIERR_NONE) { return rslt; } rslt = DbiOpenTable(*phDb, (pCHAR) szTblLookup, (pCHAR) szTblType, NULL, NULL, 0, dbiREADWRITE, dbiOPENSHARED, xltFIELD, FALSE, NULL, &hCur); if (ChkRslt(rslt, "OpenTable") != DBIERR_NONE) { return rslt; } // Add some records into the lookup table. AddLKRecord(hCur, "2001"); AddLKRecord(hCur, "2002"); AddLKRecord(hCur, "2003"); AddLKRecord(hCur, "2004"); AddLKRecord(hCur, "2005"); AddLKRecord(hCur, "2006"); AddLKRecord(hCur, "2007"); // Close the table so it can be reopened from the calling function. rslt = DbiCloseCursor(&hCur); ChkRslt(rslt, "CloseCursor"); return rslt; } //===================================================================== // Function: // AddRecord(hCur, pszName, lEmpNum, lDeptNum, lBuildNum, // pszSSNum, pszCube); // // Input: hCur - Pointer to the cursor handle // pszName - Name // lEmpNum - Employee number // lDeptNum - Dept number // lBuildNum - Building number // pszSSNum - SS number // pszCube - Cube number // // Return: Result of adding the record to the table // // Description: // This function will add a record to the given table. //===================================================================== DBIResult AddRecord (hDBICur hCur, pCHAR pszName, INT16 lEmpNum, INT16 lDeptNum, INT16 lBuildNum, pCHAR pszSSNum, pCHAR pszCube) { DBIResult rslt; // Value returned from IDAPI functions CURProps TblProps; // Table properties pBYTE pRecBuf; // Record buffer // Allocate a record buffer. rslt = DbiGetCursorProps(hCur, &TblProps); ChkRslt(rslt, "GetCursorProps"); pRecBuf = (pBYTE) malloc(TblProps.iRecBufSize * sizeof(BYTE)); if (pRecBuf == NULL) { return DBIERR_NOMEMORY; } // Initialize record buffer. rslt = DbiInitRecord(hCur, pRecBuf); ChkRslt(rslt, "InitRecord"); // First name. rslt = DbiPutField(hCur, 1, pRecBuf, (pBYTE) pszName); ChkRslt(rslt, "PutField"); // Employee number. rslt = DbiPutField(hCur, 2, pRecBuf, (pBYTE) &lEmpNum); ChkRslt(rslt, "PutField"); // Department number. rslt = DbiPutField(hCur, 3, pRecBuf, (pBYTE) &lDeptNum); ChkRslt(rslt, "PutField"); // Building number. If NULL, allow the default value to be used. if (lBuildNum != NULL) { rslt = DbiPutField(hCur, 4, pRecBuf, (pBYTE) &lBuildNum); ChkRslt(rslt, "PutField"); } // SS number. rslt = DbiPutField(hCur, 5, pRecBuf, (pBYTE) pszSSNum); ChkRslt(rslt, "PutField"); // Place of birth. rslt = DbiPutField(hCur, 6, pRecBuf, (pBYTE) pszCube); ChkRslt(rslt, "PutField"); // Write the record to disk. rslt = DbiInsertRecord(hCur, dbiNOLOCK, pRecBuf); ChkRslt(rslt, "InsertRecord"); free(pRecBuf); return rslt; } //===================================================================== // Function: // AddLKRecord(hCur, pszCube); // // Input: hCur - Pointer to the cursor handle // pszCube - Cube name // // Return: Result of adding the record to the table // // Description: // This function will add a record to the given table. //===================================================================== DBIResult AddLKRecord (hDBICur hCur, pCHAR pszCube) { DBIResult rslt; // Value returned from IDAPI functions CURProps TblProps; // Table properties pBYTE pRecBuf; // Record buffer // Allocate a record buffer. rslt = DbiGetCursorProps(hCur, &TblProps); ChkRslt(rslt, "GetCursorProps"); pRecBuf = (pBYTE) malloc(TblProps.iRecBufSize * sizeof(BYTE)); if (pRecBuf == NULL) { return DBIERR_NOMEMORY; } // Initialize the record buffer. rslt = DbiInitRecord(hCur, pRecBuf); ChkRslt(rslt, "InitRecord"); // Cube number. rslt = DbiPutField(hCur, 1, pRecBuf, (pBYTE) pszCube); ChkRslt(rslt, "PutField"); // Write the record to disk.. rslt = DbiInsertRecord(hCur, dbiNOLOCK, pRecBuf); ChkRslt(rslt, "InsertRecord"); free(pRecBuf); return rslt; } //===================================================================== // Function: // FindRecord(pszString, hCur); // // Input: pszString - String to find in the first field // hCur - Cursor handle // // Return: Result of the search // // Description: // This function will search the given table for the string // passed to it in the first parameter. It will place this // string into the first field of the record buffer and search // for the string using the record buffer. //===================================================================== DBIResult FindRecord (pCHAR pszString, hDBICur hCur) { CURProps TblProps; // Table properties pBYTE pBuf = NULL; // Pointer to the record buffer DBIResult rslt; // Return value from IDAPI functions // Create the key buffer. The size comes from the property iRecBufSize. rslt = DbiGetCursorProps(hCur,&TblProps); ChkRslt(rslt, "GetCursorProps"); pBuf = (pBYTE) malloc(TblProps.iRecBufSize); if (pBuf == NULL) { Screen(" Error - Out of memory"); return DBIERR_NOMEMORY; } // Search the "First Name" field for the pszString value. rslt = DbiPutField(hCur, 1, pBuf, (pBYTE) pszString); ChkRslt(rslt, "PutField"); rslt = DbiSetToKey(hCur, keySEARCHEQ, FALSE, 0, 0, pBuf); ChkRslt(rslt, "SetToKey"); free(pBuf); return rslt; } //===================================================================== // Function: // FormatPic(pszDest, pszPicture, pszData); // // Input: pszDest - Pointer to buffer that will receive the formatted // string // pszPicture - Pointer to buffer that holds the picture the data. // pszData - Pointer to buffer that holds the data to be // converted // // Return: A string in pszDest that matches the picture // // Description: // This function only works for pictures that have a '#' symbol // in them. This function can be expanded to work with all of // the pictures that IDAPI provides. IDAPI does not actually // format the string itself. This function expects that the // pszDest variable will be large enough to hold the string after // conversion. Therefore, the length of the pszDest variable must // be the length of the picture plus 1 for the NULL terminating // character. //===================================================================== void FormatPic (pCHAR pszDest, pCHAR pszPicture, pCHAR pszData) { UINT16 iDest = 0; UINT16 iPic = 0; UINT16 iData = 0; // Loop through the whole picture string and convert the data string to // conform to it. while (pszPicture[iPic] != NULL) { // If the character is a number put the number from the pszData string // into the StrDest string. if (pszPicture[iPic] == '#') { // Clean up the string one character at a time. pszDest[iDest] = pszData[iData]; iDest++; iPic++; iData++; } // Otherwise the character is a constant to be placed within // the string. else { // Clean up the string one character at a time. pszDest[iDest] = pszPicture[iPic]; iDest++; iPic++; } } pszDest[iDest] = 0; }