// BDE - (C) Copyright 1995 by Borland International // storproc.c #include "snipit.h" static pCHAR szTblName = "STORPROC"; // 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 12, // 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, 12, 0, 0, 0, 0, fldvNOCHECKS, fldrREADWRITE } }; // Index Descriptor - describes the index associated with the table. static IDXDesc IdxDesc = { { "PROCIDX" }, // 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); static DBIResult AddRecord(hDBICur hCur, pCHAR pFirst, pCHAR pLast); static DBIResult CreateProcedure(hDBIDb hDb); static const UINT16 uNumFields = sizeof(fldDesc) / sizeof (fldDesc[0]); //===================================================================== // Function: // StoredProcedures(); // // Description: // This file shows how to create, use, and get information on // stored procedures. Note that the syntax for stored procedure // creation is specific to a given server. //===================================================================== void StoredProcedures (void) { hDBIDb hDb; // Handle to the database. DBIResult rslt; // Return value from IDAPI functions. BOOL bProcs; // Supports stored procedures? hDBICur hCur; // Cursor Handle. SPParamDesc spParamDesc; // Used to determine size of record Buffer, // and number of paramaters. pSPParamDesc pspParamDesc; // Holds info on all parameters. pBYTE pRecBuf; // Record buffer. UINT16 iCount; // Current Parameter UINT16 iRecBufSize; // Size of the record DBINAME szProcName; // Name of the procedure hDBIStmt hStmt; // Statement handle UINT16 uLength; // Length of the property int i; // Loop counter CHAR szDelete[] = "DROP PROCEDURE PROCTEST"; // Statement to delete the procedure Screen("*** Stored Procedure Example ***\r\n"); BREAK_IN_DEBUGGER(); Screen(" Initializing IDAPI..."); if (InitAndConnect2(&hDb) != DBIERR_NONE) { Screen("\r\n*** End of Example ***"); return; } rslt = DbiGetProp(hDb, dbPROCEDURES, &bProcs, sizeof(bProcs), &uLength); ChkRslt(rslt, "GetProp"); if (!bProcs) { Screen("\r\n Error - specified server does not support stored" " procedures."); Screen(" Close the database and exit IDAPI..."); CloseDbAndExit(&hDb); Screen("\r\n*** End of Example ***"); return; } rslt = CreateSQLTable(hDb, szTblName); if (rslt) { Screen(" Close the database and exit IDAPI..."); CloseDbAndExit(&hDb); Screen("\r\n*** End of Example ***"); return; } rslt = DbiSetProp(hDb, dbPARAMFMTQMARK, TRUE); ChkRslt(rslt, "SetProp"); rslt = CreateProcedure(hDb); if (rslt) { Screen("\r\n Drop the procedure..."); rslt = DbiQExecDirect(hDb, qrylangSQL, szDelete, NULL); ChkRslt(rslt, "QExecDirect"); Screen(" Delete the table..."); rslt = DbiDeleteTable(hDb, szTblName, NULL); ChkRslt(rslt, "DeleteTable"); Screen(" Close the database and exit IDAPI..."); CloseDbAndExit(&hDb); Screen("\r\n*** End of Example ***"); return; } Screen(" Display the list of procedures..."); rslt = DbiOpenSPList(hDb, FALSE, TRUE, NULL, &hCur); ChkRslt(rslt, "OpenSPList"); if (hCur) { DisplayInMemoryTable(hCur, 0); rslt = DbiCloseCursor(&hCur); ChkRslt(rslt, "CloseCursor"); } strcpy(szProcName, "PROCTEST"); Screen("\r\n Display information about the parameters to" " the procedure..."); rslt = DbiOpenSPParamList(hDb, szProcName, FALSE, 0, &hCur); ChkRslt(rslt, "OpenSPParamList"); if (hCur) { DisplayInMemoryTable(hCur, 0); rslt = DbiSetToEnd(hCur); ChkRslt(rslt, "SetToEnd"); // Get the last property to determine the count of properties... rslt = DbiGetPriorRecord(hCur, dbiNOLOCK, (pBYTE)&spParamDesc, NULL); ChkRslt(rslt, "GetPriorRecord"); pspParamDesc = (pSPParamDesc)malloc((spParamDesc.uParamNum + 1) * sizeof(SPParamDesc)); memset((pVOID)pspParamDesc, 0, spParamDesc.uParamNum * sizeof(SPParamDesc)); rslt = DbiSetToBegin(hCur); ChkRslt(rslt, "SetToBegin"); // Get descriptors for each field iRecBufSize = 0; iCount = 0; while ((rslt = DbiGetNextRecord(hCur, dbiNOLOCK, (pBYTE)&(pspParamDesc[iCount]), NULL)) == DBIERR_NONE) { // Oracle CHAR parameters are unsized... if (pspParamDesc[iCount].uFldType == fldZSTRING) { if (pspParamDesc[iCount].iUnits1 == 0) { pspParamDesc[iCount].iUnits1 = 12; } pspParamDesc[iCount].uLen = pspParamDesc[iCount].iUnits1 + 1; } if (pspParamDesc[iCount].uFldType == fldBOOL) { pspParamDesc[iCount].uLen = 2; } if (pspParamDesc[iCount].uFldType == fldINT32) { pspParamDesc[iCount].uLen = 4; } iRecBufSize = iRecBufSize + pspParamDesc[iCount].uLen; pspParamDesc[iCount].szName[0] = 0; if (iCount) { pspParamDesc[iCount].uOffset = pspParamDesc[iCount - 1].uOffset + pspParamDesc[iCount - 1].uLen; } iCount++; } if (rslt != DBIERR_EOF) { Screen("\r\n"); ChkRslt(rslt, "GetNextRecord"); } // Allocate space for the record buffer and parameters pRecBuf = (pBYTE)malloc(iRecBufSize * sizeof(CHAR)); if (!pRecBuf) { rslt = DbiCloseCursor(&hCur); ChkRslt(rslt, "CloseCursor"); Screen("\r\n Drop the procedure..."); rslt = DbiQExecDirect(hDb, qrylangSQL, szDelete, NULL); ChkRslt(rslt, "QExecDirect"); rslt = DbiDeleteTable(hDb, szTblName, NULL); ChkRslt(rslt, "DeleteTable"); Screen(" Error - Out of memory"); CloseDbAndExit(&hDb); return; } memset((pVOID)pRecBuf, 0, iRecBufSize); // Set the input parameter - this is done for Sybase, as // in/out information is not returned for parameters to // stored procedures on Sybase. i = 0; while ((i < iCount) && ((pspParamDesc[i].eParamType != paramIN) && (pspParamDesc[i].eParamType != paramINOUT) && (pspParamDesc[i].eParamType != paramUNKNOWN))) { i++; } if (pspParamDesc[i].eParamType == paramUNKNOWN) { pspParamDesc[i].eParamType = paramIN; } if (i < iCount) { memcpy((pVOID)(pRecBuf + pspParamDesc[i].uOffset), "Wong", 4); rslt = DbiCloseCursor(&hCur); ChkRslt(rslt, "CloseCursor"); Screen("\r\n Execute the procedure..."); // Could also use DbiQExecProcDirect: // rslt = DbiQExecProcDirect(hDb, szProcName, iCount, pspParamDesc, // pRecBuf, &hCur); rslt = DbiQPrepareProc(hDb, szProcName, iCount, pspParamDesc, NULL, &hStmt); ChkRslt(rslt, "QPrepareProc"); rslt = DbiQSetProcParams(hStmt, iCount, pspParamDesc, pRecBuf); ChkRslt(rslt, "QSetProcParams"); // For InterBase only: // Can also use the following syntax to get the results // of a procedure in the forum of a cursor: // // 'select * from ; rslt = DbiQExec(hStmt, &hCur); ChkRslt(rslt, "QExec"); if (hCur) { Screen("\r\n Return Values:"); DisplayTable(hCur, 0); rslt = DbiCloseCursor(&hCur); ChkRslt(rslt, "CloseCursor"); } else if (rslt == DBIERR_NONE) { Screen("\r\n Return Values:\r\n"); Screen(" First Name: %s", &(pRecBuf[pspParamDesc[1].uOffset])); Screen(" Last Name: %s", &(pRecBuf[pspParamDesc[2].uOffset])); } rslt = DbiQFree(&hStmt); ChkRslt(rslt, "QFree"); } else { Screen("\r\n Error - no input parameter..."); } } if (pRecBuf) { free(pRecBuf); } if (pspParamDesc) { free(pspParamDesc); } Screen("\r\n Drop the procedure..."); rslt = DbiQExecDirect(hDb, qrylangSQL, szDelete, NULL); ChkRslt(rslt, "QExecDirect"); rslt = DbiDeleteTable(hDb, szTblName, NULL); ChkRslt(rslt, "DeleteTable"); Screen(" Close the database and exit IDAPI..."); CloseDbAndExit(&hDb); Screen("\r\n*** End of Example ***"); } //===================================================================== // Function: // CreateSQLTable(hDb, pszTblName); // // Input: phDb - Pointer to the database handle. // pszTblName - The name of the table to create. // // Return: Result returned by IDAPI. // // Description: // This function will create a table and add records to that // table. //===================================================================== DBIResult CreateSQLTable (hDBIDb hDb, pCHAR pszTblName) { DBIResult rslt; // Value returned from IDAPI functions CRTblDesc crTblDesc; // Table Descriptor hDBICur hCur; // Cursor used for adding records // 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; Screen(" Creating the table..."); rslt = DbiCreateTable(hDb, TRUE, &crTblDesc); if (ChkRslt(rslt, "CreateTable") != DBIERR_NONE) { return rslt; } rslt = DbiOpenTable(hDb, pszTblName, NULL, NULL, NULL, 0, dbiREADWRITE, dbiOPENSHARED, xltFIELD, FALSE, NULL, &hCur); if (ChkRslt(rslt, "OpenTable") != DBIERR_NONE) { rslt = DbiDeleteTable(hDb, pszTblName, NULL); ChkRslt(rslt, "DeleteTable"); return rslt; } // Add records to the table. Screen(" Adding records to the table..."); rslt = AddRecord(hCur, "Tom", "Smith"); rslt = AddRecord(hCur, "Jim", "Jones"); rslt = AddRecord(hCur, "Larry", "Peterson"); rslt = AddRecord(hCur, "Jane", "Jackson"); rslt = AddRecord(hCur, "Mary", "Wong"); rslt = DbiCloseCursor(&hCur); ChkRslt(rslt, "ClostTable"); return rslt; } //===================================================================== // Function: // AddRecord (hDBICur hCur, pCHAR pFirst, pCHAR pLast) // // Input: hCur - The table handle // pFirst - First Name // pLast - Last Name // // Return: Result of adding the record to the table // // Description: // Insert a record into the table. //===================================================================== DBIResult AddRecord (hDBICur hCur, pCHAR pFirst, pCHAR pLast) { DBIResult rslt; // Return value from IDAPI functions pBYTE pRecBuf; // Record buffer CURProps TblProps; // Table properties // Allocate a record buffer. rslt = DbiGetCursorProps(hCur, &TblProps); ChkRslt(rslt, "GetCursorProps"); pRecBuf = (pBYTE) malloc(TblProps.iRecBufSize * sizeof(BYTE)); if (pRecBuf == NULL) { Screen(" Error - Out of memory"); return DBIERR_NOMEMORY; } // Clear the record buffer, then add the data. rslt = DbiInitRecord(hCur, pRecBuf); ChkRslt(rslt, "InitRecord"); rslt = DbiPutField(hCur, 1, pRecBuf, (pBYTE) pFirst); ChkRslt(rslt, "PutField"); rslt = DbiPutField(hCur, 2, pRecBuf, (pBYTE) pLast); ChkRslt(rslt, "PutField"); rslt = DbiInsertRecord(hCur, dbiNOLOCK, pRecBuf); ChkRslt(rslt, "InsertRecord"); free(pRecBuf); return rslt; } //===================================================================== // Function: // CreateProcedure (hDBIDb hDb) // // Input: hDb - Handle to the Database // // Return: Result of creating the procedure // // Description: // This function is used to create a stored procedure on a // given server. As each server has it's own specific syntax // for creating stored procedures, this function determines // the type of the server and uses the appropriate syntax. //===================================================================== DBIResult CreateProcedure (hDBIDb hDb) { DBIResult rslt = DBIERR_NONE; // Return value from BDE DBINAME szDbType; // Type of the server UINT16 uLength; // Length of the property pCHAR szCreate = NULL; // SQL Statment to pass to // DbiQExecDirect CHAR szCreateIB[] = // Syntax for InterBase "CREATE PROCEDURE PROCTEST (LAST VARCHAR(12))\r\n" "RETURNS (FIRSTNAME VARCHAR(10),\r\n" " LASTNAME VARCHAR(12))\r\n" "AS\r\n" "BEGIN\r\n" " FOR select * from STORPROC s\r\n" " where s.LASTNAME = :LAST\r\n" " INTO :FIRSTNAME, :LASTNAME\r\n" " DO\r\n" " SUSPEND;\r\n" "END;\r\n"; CHAR szCreateOra [] = // Syntax for Oracle "CREATE PROCEDURE PROCTEST (LNAME IN VARCHAR,\r\n" " FRST OUT VARCHAR,\r\n" " LST OUT VARCHAR)\r\n" "AS BEGIN\r\n" " select FRSTNAME, LASTNAME into FRST, LST from STORPROC\r\n" " where LASTNAME = LNAME;\r\n" "END PROCTEST;\r\n"; CHAR szCreateSyb [] = // Syntax for Sybase "CREATE PROCEDURE PROCTEST @LNAME varchar(12)\r\n" "as\r\n" " select s.FRSTNAME, s.LASTNAME from STORPROC s\r\n" " where s.LASTNAME = @LNAME\r\n"; rslt = DbiGetProp(hDb, dbDATABASETYPE, &szDbType, DBIMAXNAMELEN, &uLength); ChkRslt(rslt, "GetProp"); if (!strcmp(szDbType, "INTRBASE")) { szCreate = szCreateIB; } else { if (!strcmp(szDbType, "ORACLE")) { szCreate = szCreateOra; } else { if (!strcmp(szDbType, "SYBASE")) { szCreate = szCreateSyb; } } } if (szCreate) { Screen("\r\n Create the procedure with the following query:" "\r\n\r\n%s...", szCreate); rslt = DbiQExecDirect(hDb, qrylangSQL, szCreate, NULL); ChkRslt(rslt, "QExecDirect"); } else { Screen(" Error - server not supported."); // Force an error rslt = 1; } return rslt; }