// BDE - (C) Copyright 1995 by Borland International // Sqlbind.C #include "snipit.h" static pCHAR szTblName = "SQLBIND"; // Field Descriptor used in creating a table. static SNIPFAR FLDDesc fldDesc[] = { { // Field 1 - FRSTNAME 1, // Field Number "FRSTNAME", // Field Name fldZSTRING, // Field Type fldUNKNOWN, // Field Subtype 10, // 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, // Validiy checks ( 0 ) fldrREADWRITE // Rights }, { // Field 2 - LASTNAME 2, "LASTNAME", fldZSTRING, fldUNKNOWN, 10, 0, 0, 0, 0, fldvNOCHECKS, fldrREADWRITE }, { // Field 3 - AGE 3, "AGE", fldFLOAT, fldUNKNOWN, 0, 0, 0, 0, 0, fldvNOCHECKS, fldrREADWRITE } }; // Index Descriptor - describes the index associated with the table. static IDXDesc IdxDesc = { { "BaseIdx" }, // Name 1, // Number { NULL }, // Tag name (dBASE only) { NULL }, // Optional format FALSE, // Primary? TRUE, // Unique? FALSE, // Descending? TRUE, // Maintained? FALSE, // SubSet? FALSE, // Expression index? NULL, // for QBE only 2, // Fields in key NULL, // Length in bytes FALSE, // Index out of date? 0, // Key Type of Expression { 2, 1 }, // Array of field numbers { NULL }, // Key expression { NULL }, // Key Condition FALSE, // Case insensitive 0, // Block size in bytes 0 // Restructure number }; // Function prototypes static DBIResult CreateSQLTable(hDBIDb hDb, pCHAR pszTblName, pCHAR pszDbType); static void CleanUp(pBYTE pRecBuf, pFLDDesc pfldDesc, hDBIStmt *hStmt, hDBIDb *hDb, hDBICur *hCur, hDBICur *hAnsCur, pCHAR szTblName, hDBIXact hTran, CHAR *pszDbType); static const UINT16 uNumFields = sizeof(fldDesc) / sizeof (fldDesc[0]); //===================================================================== // Function: // SQLBind(); // // Description: // This example shows how to use Parameter Binding with Query's. // Parameter binding allows you to re-execute a SQL query with // different parameters without having to prepare the query // (which is done by calling DbiQPrepareExt) over and over.... // This can result in dramatic speed improvements. // // This sample shows two examples which search for values in a // table: // Example 1: The table has been opened. The table's // field description structure and record buffer are // used to define the parameter values for DbiQSetParams(). // This method is useful if the parameters in the SQL // query exactly match the field descriptions for the // table, as is often found in Inserts and updates. This // example inserts records into the table // // Example 2: The table has been opened. The table's // field description structure and record buffer are // used to define the parameter values for DbiQSetParams(). // This method is useful if the parameters in the SQL // query exactly match the field descriptions for the // table, as is often found in Inserts and updates. This // example retreives records matching a certain criterion. // // Example 3: The table has not been opened. The client // builds the logical field description structure and record // buffer used to define the parameter values for // DbiQSetParams(). // // WARNING: This example requires write access to the database. //===================================================================== void SQLBind (void) { hDBIDb hDb = NULL; // Handle to the Database. hDBICur hCur = NULL; // Handle to the Table. hDBICur hAnsCur = NULL; // Handle to the Answer Set pCHAR pszDbType = NULL; // Type of the Database DBIResult rslt; // Return value from IDAPI functions UINT16 uLength; // Length of property return from // DbiGetProp hDBIStmt hStmt = NULL; // Handle to the Query Statement CURProps curProps; // Table Properties pBYTE pRecBuf = NULL; // Record Buffer pFLDDesc pfldDesc = NULL, // Field Descriptor for the Table pfldDescT; UINT16 uParam, uParams; // Number of parameters UINT16 uRecBufSize; // Record buffer size hDBIXact hTran = 0; // Transaction handle DFLOAT age; // Variable for Age int i; // Loop counter CHAR szInsert[] = { // SQL statement for insert "INSERT INTO SQLBIND (FRSTNAME, LASTNAME, AGE) VALUES" "(?, ?, ?)" }; CHAR szQry1[] = { // SQL statement for Example 1 "SELECT * FROM SQLBIND " "WHERE FRSTNAME = ? and LASTNAME = ?" }; CHAR szQry2[] = { // SQL statement for Example 2 "SELECT * FROM SQLBIND " "WHERE FRSTNAME = ? or FRSTNAME = ?" }; Screen("*** SQL Parameter Binding Example ***\r\n"); BREAK_IN_DEBUGGER(); Screen(" Initializing IDAPI..."); if (InitAndConnect2(&hDb) != DBIERR_NONE) { Screen("\r\n*** End of Example ***"); return; } pszDbType = (pCHAR)malloc(sizeof(BYTE) * DBIMAXNAMELEN); if (!pszDbType) { Screen("\r\n Out Of memory!"); CloseDbAndExit(&hDb); Screen("\r\n*** End of Example ***"); return; } // Set the type of the table - NULL for server database, // database specific value for local tables. Used in // creating and deleting the table. rslt = DbiGetProp(hDb, dbDATABASETYPE, pszDbType, sizeof(DBINAME), &uLength); ChkRslt(rslt, "GetProp"); if (!strcmp(pszDbType, "STANDARD")) { rslt = DbiGetProp(hDb, dbDEFAULTDRIVER, pszDbType, sizeof(DBINAME), &uLength); ChkRslt(rslt, "GetProp"); if (!strcmp(pszDbType, "")) { strcpy(pszDbType, szPARADOX); } } else { free(pszDbType); pszDbType = NULL; } // Create the table if (CreateSQLTable(hDb, szTblName, pszDbType) != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } // Only allow '?' as a parameter marker. Valid only for remote databases. if (!pszDbType) { rslt = DbiSetProp((hDBIObj)hDb, dbPARAMFMTQMARK, TRUE); ChkRslt(rslt, "SetProp"); } rslt = DbiOpenTable(hDb, szTblName, pszDbType, NULL, NULL, 0, dbiREADWRITE, dbiOPENSHARED, xltFIELD, FALSE, NULL, &hCur); if (ChkRslt(rslt, "OpenTable") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } // Set up Record buffer and Field Descriptor. rslt = DbiGetCursorProps(hCur, &curProps); ChkRslt(rslt, "GetCursorProps"); // Need to use iRecSize as we are directly modifying the record buffer uRecBufSize = (UINT16)(curProps.iRecSize * sizeof(BYTE)); pRecBuf = (pBYTE) malloc(uRecBufSize); pfldDesc = (pFLDDesc) malloc(curProps.iFields * sizeof(FLDDesc)); if ((!pfldDesc) || (!pRecBuf)) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } rslt = DbiGetFieldDescs(hCur, pfldDesc); ChkRslt(rslt, "GetFieldDescs"); // Make certain field numbers are not set for (i=0; i < curProps.iFields; i++) { pfldDesc[i].szName[0] = 0; } uParams = curProps.iFields; /////////////////////////////////////////////////////////////////////// // EXAMPLE 1: Table is open. Use field descriptions and // record buffer. // // INSERT INTO SQLBIND (FRSTNAME, LASTNAME) VALUES (?, ?) rslt = DbiBeginTran(hDb, xilREADCOMMITTED, &hTran); ChkRslt(rslt, "BeginTran"); Screen("\r\n Prepare the SQL insert statement..."); rslt = DbiQPrepareExt(hDb, qrylangSQL, szInsert, qprepNONE, &hStmt); ChkRslt(rslt, "QPrepareExt"); Screen(" Insert some records using the following SQL statement:\r\n"); Screen(" %s\r\n", szInsert); memset((void*)pRecBuf, 0, uRecBufSize); memcpy((void*)(pRecBuf + pfldDesc[0].iOffset), "Tracy", 5); memcpy((void*)(pRecBuf + pfldDesc[1].iOffset), "Smith", 5); age = 24; memcpy((void*)(pRecBuf + pfldDesc[2].iOffset), &age, sizeof(age)); rslt = DbiQSetParams(hStmt, uParams, pfldDesc, pRecBuf); if (ChkRslt(rslt, "QSetParams") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } rslt = DbiQExec(hStmt, NULL); if (ChkRslt(rslt, "QExec") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } memset((void*)pRecBuf, 0, uRecBufSize); memcpy((void*)(pRecBuf + pfldDesc[0].iOffset), "David", 5); memcpy((void*)(pRecBuf + pfldDesc[1].iOffset), "Duncan", 6); age = 29; memcpy((void*)(pRecBuf + pfldDesc[2].iOffset), &age, sizeof(age)); rslt = DbiQSetParams(hStmt, uParams, pfldDesc, pRecBuf); if (ChkRslt(rslt, "QSetParams") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } rslt = DbiQExec(hStmt, NULL); if (ChkRslt(rslt, "QExec") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } memset((void*)pRecBuf, 0, uRecBufSize); memcpy((void*)(pRecBuf + pfldDesc[0].iOffset), "John", 4); memcpy((void*)(pRecBuf + pfldDesc[1].iOffset), "Brisco", 6); age = 46; memcpy((void*)(pRecBuf + pfldDesc[2].iOffset), &age, sizeof(age)); rslt = DbiQSetParams(hStmt, uParams, pfldDesc, pRecBuf); if (ChkRslt(rslt, "QSetParams") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } rslt = DbiQExec(hStmt, NULL); if (ChkRslt(rslt, "QExec") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } rslt = DbiQFree(&hStmt); ChkRslt(rslt, "QFree"); rslt = DbiEndTran(hDb, hTran, xendCOMMIT); ChkRslt(rslt, "EndTran"); /////////////////////////////////////////////////////////////////////// // EXAMPLE 2: Table is open. Use field descriptions and // record buffer. // // SELECT * FROM SQLBind WHERE FRSTNAME = ? and LASTNAME = ? uParams = 2; rslt = DbiBeginTran(hDb, xilREADCOMMITTED, &hTran); ChkRslt(rslt, "BeginTran"); Screen(" Perform the following SQL statement on the table:\r\n"); Screen(" %s", szQry1); Screen("\r\n Prepare the SQL statement..."); rslt = DbiQPrepareExt(hDb, qrylangSQL, szQry1, qprepNONE, &hStmt); ChkRslt(rslt, "QPrepare"); Screen("\r\n Search for Tracy Smith"); memset((void *)pRecBuf, 0, uRecBufSize); memcpy((pVOID)(pRecBuf + pfldDesc[0].iOffset), "Tracy", 5); memcpy((pVOID)(pRecBuf + pfldDesc[1].iOffset), "Smith", 5); Screen(" Set the Statement Parameters..."); rslt = DbiQSetParams(hStmt, uParams, pfldDesc, pRecBuf); if (ChkRslt(rslt, "QSetParams") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } Screen(" Execute the SQL statement..."); rslt = DbiQExec(hStmt, &hAnsCur); if (ChkRslt(rslt, "QExec") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } // Check for a valid cursor if (hAnsCur) { Screen(" Display the answer table..."); rslt = DbiSetToBegin(hAnsCur); ChkRslt(rslt, "SetToBegin"); DisplayTable(hAnsCur, 0); Screen("\r\n Close the cursor to the answer set..."); rslt = DbiCloseCursor(&hAnsCur); ChkRslt(rslt, "CloseCursor"); hAnsCur = 0; } else { Screen(" Could not get cursor to the answer table"); } Screen("\r\n Search for John Brisco"); Screen(" Note that we do not have to call DbiQPrepareExt..."); memset((void*)pRecBuf, 0, uRecBufSize); memcpy((void*)(pRecBuf + pfldDesc[0].iOffset), "John", 4); memcpy((void*)(pRecBuf + pfldDesc[1].iOffset), "Brisco", 6); Screen(" Set the Statement Parameters..."); rslt = DbiQSetParams(hStmt, uParams, pfldDesc, pRecBuf); if (ChkRslt(rslt, "QSetParams") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } Screen(" Execute the SQL statement..."); rslt = DbiQExec(hStmt, &hAnsCur); if (ChkRslt(rslt, "QExec") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } // Check for a valid cursor if (hAnsCur) { Screen(" Display the answer table..."); rslt = DbiSetToBegin(hAnsCur); ChkRslt(rslt, "SetToBegin"); DisplayTable(hAnsCur, 0); Screen("\r\n Close the cursor to the answer set..."); rslt = DbiCloseCursor(&hAnsCur); ChkRslt(rslt, "CloseCursor"); hAnsCur = 0; } else { Screen(" Could not get cursor to the answer table"); } Screen(" Release memory allocated for the Query..."); rslt = DbiQFree(&hStmt); ChkRslt(rslt, "QryFree"); if (pRecBuf) { free(pRecBuf); pRecBuf = NULL; } if (pfldDesc) { free(pfldDesc); } rslt = DbiEndTran(hDb, hTran, xendCOMMIT); ChkRslt(rslt, "EndTran"); Screen(" Close the %s table...", szTblName); rslt = DbiCloseCursor(&hCur); ChkRslt(rslt, "CloseCursor"); hCur = 0; /////////////////////////////////////////////////////////// // EXAMPLE 3: Table is not open. Use client-generated // logical field descriptions and record buffer. // // SELECT * FROM SQLBind WHERE FRSTNAME = ? or FRSTNAME = ? rslt = DbiBeginTran(hDb, xilREADCOMMITTED, &hTran); ChkRslt(rslt, "BeginTran"); uParams = 2; pfldDesc = (pFLDDesc) malloc(uParams * sizeof(FLDDesc)); if (pfldDesc == NULL) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } memset(pfldDesc, 0, uParams * sizeof(FLDDesc)); // Build the logical field descriptions to pass to DbiQSetParams(). for (pfldDescT = pfldDesc, uParam = 0; uParam < uParams; uParam++, pfldDescT++) { // The following fields must be set correctly: // iFldNum - field (parameter) number. // iFldType - field type. // iUnits1 - required for string fields only. // iLen - for logical types, sizeof (iFldType) or // iUnits1 + 1 for string types. // iOffset - offset in the record buffer with param value. pfldDescT->iFldNum = (UINT16)(uParam + 1); pfldDescT->iFldType = fldZSTRING; // IDAPI logical type. pfldDescT->iUnits1 = 10; // Units. pfldDescT->iLen = 11; // Add 1 for NULL term. pfldDescT->iOffset = (UINT16)(uParam ? pfldDesc[uParam-1].iOffset + pfldDesc[uParam-1].iLen : 0); } uRecBufSize = (UINT16)(pfldDesc[uParams-1].iOffset + pfldDesc[uParams-1].iLen); pRecBuf = (pBYTE) malloc(uRecBufSize * sizeof(BYTE)); if (!pRecBuf) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } memset(pRecBuf, 0, uRecBufSize); Screen("\r\n Prepare the SQL statement..."); rslt = DbiQPrepareExt(hDb, qrylangSQL, szQry2, qprepNONE, &hStmt); ChkRslt(rslt, "QPrepare"); Screen(" Perform the following SQL statement on the table:\r\n"); Screen(" %s", szQry2); Screen("\r\n Search for Tracy or David "); // Place parameter values in IDAPI logical format into the record buffer Screen(" Set the Statement Parameters..."); memcpy((pVOID)(pRecBuf + pfldDesc[0].iOffset), "Tracy", 5); memcpy((pVOID)(pRecBuf + pfldDesc[1].iOffset), "David", 5); rslt = DbiQSetParams(hStmt, uParams, pfldDesc, pRecBuf); if (ChkRslt(rslt, "QSetParams") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } Screen(" Execute the SQL statement..."); rslt = DbiQExec(hStmt, &hAnsCur); if (ChkRslt(rslt, "QExec") != DBIERR_NONE) { CleanUp(pRecBuf, pfldDesc, &hStmt, &hDb, &hCur, &hAnsCur, szTblName, hTran, pszDbType); return; } // Check for a valid cursor if (hAnsCur) { Screen(" Display the answer table..."); rslt = DbiSetToBegin(hAnsCur); ChkRslt(rslt, "SetToBegin"); DisplayTable(hAnsCur, 0); Screen("\r\n Close the cursor to the answer set..."); rslt = DbiCloseCursor(&hAnsCur); ChkRslt(rslt, "CloseCursor"); hAnsCur = 0; } else { Screen(" Could not get cursor to the answer table"); } rslt = DbiQFree(&hStmt); ChkRslt(rslt, "QFree"); rslt = DbiEndTran(hDb, hTran, xendCOMMIT); ChkRslt(rslt, "EndTran"); // Cleanup Screen(" Delete the table..."); rslt = DbiDeleteTable(hDb, szTblName, pszDbType); ChkRslt(rslt, "DeleteTable"); Screen(" Close the Database and exit IDAPI..."); CloseDbAndExit(&hDb); if (pRecBuf) { free(pRecBuf); } if (pfldDesc) { free(pfldDesc); } if (pszDbType) { free(pszDbType); } Screen("\r\n*** End of Example ***"); } //===================================================================== // Function: // CreateSQLTable(hDb, pszTblName, pszDbType); // // Input: phDb - Pointer to the database handle. // pszTblName - The name of the table to create. // pszDbType - Type of table to create (Null for Remote tables) // // Return: Result returned by IDAPI. // // Description: // This function will create a table on the specified // database. //===================================================================== DBIResult CreateSQLTable (hDBIDb hDb, pCHAR pszTblName, pCHAR pszDbType) { DBIResult rslt; // Value returned from IDAPI functions CRTblDesc crTblDesc; // Table Descriptor // Initialize the Table Create Descriptor. memset(&crTblDesc, 0, sizeof(CRTblDesc)); strcpy(crTblDesc.szTblName, pszTblName); crTblDesc.iFldCount = uNumFields; crTblDesc.pfldDesc = fldDesc; crTblDesc.iIdxCount = 1; crTblDesc.pidxDesc = &IdxDesc; // If a local table if (pszDbType) { // Set the Table Type. strcpy(crTblDesc.szTblType, pszDbType); // No Indexes crTblDesc.iIdxCount = 0; crTblDesc.pidxDesc = NULL; if (!strcmp(pszDbType, szDBASE)) { crTblDesc.pfldDesc[2].iUnits1 = 8; } } Screen(" Creating the table..."); rslt = DbiCreateTable(hDb, TRUE, &crTblDesc); if (ChkRslt(rslt, "CreateTable") != DBIERR_NONE) { return rslt; } return rslt; } //===================================================================== // Function: // CleanUp(pRecBuf, pfldDesc, hStmt, hDb, hCur, szTblName, hTran, // szDbName) // // Input: pRecBuf - Handle to the Record Buffer // pfldDesc - Field Descriptor // hStmt - Statement object // hDb - Handle to the Database // hCur - The table handle // szTblName - Name of the Table // hTran - Transaction Handle // szDbName - Database Type // // Return: None // // Description: // This function is used to free all resources allocated // within this example. //===================================================================== void CleanUp(pBYTE pRecBuf, pFLDDesc pfldDesc, hDBIStmt *hStmt, hDBIDb *hDb, hDBICur *hCur, hDBICur *hAnsCur, pCHAR szTblName, hDBIXact hTran, CHAR *pszDbType) { DBIResult rslt; // Return value from IDAPI if (*hStmt) { rslt = DbiQFree(hStmt); ChkRslt(rslt, "QryFree"); } if (*hCur) { rslt = DbiCloseCursor(hCur); ChkRslt(rslt, "CloseCursor"); } if (*hAnsCur) { rslt = DbiCloseCursor(hAnsCur); ChkRslt(rslt, "CloseCursor"); } if (hTran) { rslt = DbiEndTran(*hDb, hTran, xendABORT); ChkRslt(rslt, "EndTran"); } if (*hDb) { rslt = DbiDeleteTable(*hDb, szTblName, pszDbType); ChkRslt(rslt, "DeleteTable"); CloseDbAndExit(hDb); } if (pRecBuf) { free(pRecBuf); } if (pfldDesc) { free(pfldDesc); } Screen("\r\n*** End of Example ***"); return; }