QUIKTEST.C
//--------------------------------------------------------------------------------------- 
// 
// PROGRAM: quiktest.c 
//        This code is furnished on an as-is basis as part of the ODBC SDK and is 
//        intended for example purposes only. 
// 
//  PURPOSE: This is a Quick Test of the basic functionality of an ODBC driver. 
// 
//  FUNCTIONS: 
//     QuickTest() - performs the quick test focusing on basic functionalities. 
// 
//-------------------------------------------------------------------------------------------- 
#pragma warning (disable : 4703) 
 
#define QUIKTEST 
 
#include "autotest.h" 
#include <stdio.h> 
#include <string.h> 
#include <malloc.h> 
#include <wchar.h> 
#include <tchar.h> 
#include <time.h> 
// #include <crtdbg.h> 
#include "sql.h" 
#include "sqlext.h" 
#include "quiktest.h" 
 
//-------------------------------------------------------------------------------------- 
//  static 
//-------------------------------------------------------------------------------------- 
static TCHAR  vszFile[]= TEXT(__FILE__); 
 
static LPTSTR sz07009= TEXT("07009"); 
static LPTSTR szIM001= TEXT("IM001"); 
static LPTSTR szHYC00= TEXT("HYC00"); 
static LPTSTR szHY009= TEXT("HY009"); 
static LPTSTR szHY091= TEXT("HY091"); 
static LPTSTR szHY092= TEXT("HY092"); 
static LPTSTR szISO= TEXT("ISO 9075"); 
static LPTSTR szODBC30= TEXT("ODBC 3.0"); 
static LPTSTR szNotSupported= TEXT("did not return Not supported message"); 
static LPTSTR szSQLSETCONNECTATTR= TEXT("SQLSetConnectAttr"); 
static LPTSTR szSQLGETCONNECTATTR= TEXT("SQLGetConnecTAttr"); 
static LPTSTR szSQLGETINFO= TEXT("SQLGetInfo"); 
static LPTSTR szSQLGETTYPEINFO= TEXT("SQLGetTypeInfo"); 
static LPTSTR szSQLALLOCHANDLE= TEXT("SQLAllocHandle"); 
static LPTSTR szSQLALLOCSTMT= TEXT("SQLAllocStmt"); 
static LPTSTR szSQLALLOCCONNECT= TEXT("SQLAllocConnect"); 
static LPTSTR szSQLALLOCENV= TEXT("SQLAllocEnv"); 
static LPTSTR szSQLSETSTMTATTR= TEXT("SQLSetStmtAttr"); 
static LPTSTR szSQLGETSTMTATTR= TEXT("SQLGetStmtAttr"); 
static LPTSTR szSQLSETSTMTOPTION= TEXT("SQLSetStmtOption"); 
static LPTSTR szSQLGETSTMTOPTION= TEXT("SQLGetStmtOption"); 
static LPTSTR szSQLSETCONNECTOPTION= TEXT("SQLSetConnectOption"); 
static LPTSTR szSQLGETCONNECTOPTION= TEXT("SQLGetConnectOption"); 
static LPTSTR szSQLFETCH= TEXT("SQLFetch"); 
static LPTSTR szSQLBINDCOL= TEXT("SQLBindCol"); 
static LPTSTR szSQLFOREIGNKEYS= TEXT("SQLForeignkeys"); 
static LPTSTR szSQLFREEHANDLE= TEXT("SQLFreeHandle"); 
static LPTSTR szSQLFREECONNECT= TEXT("SQLFreeConnect"); 
static LPTSTR szSQLFREEENV= TEXT("SQLFreeEnv"); 
static LPTSTR szSQLGETDESCREC= TEXT("SQLGetDescRec"); 
static LPTSTR szSQLSETDESCREC= TEXT("SQLSetDescRec"); 
static LPTSTR szSQLGETDESCFIELD= TEXT("SQLGetDescField"); 
static LPTSTR szSQLSETDESCFIELD= TEXT("SQLSetDescField"); 
static LPTSTR szSQLCOPYDESC= TEXT("SQLCopyDesc"); 
static LPTSTR szSQLSETENVATTR= TEXT("SQLSetEnvAttr"); 
static LPTSTR szSQLGETENVATTR= TEXT("SQLGetEnvAttr"); 
static LPTSTR szSQLFREESTMT= TEXT("SQLFreeStmt"); 
static LPTSTR szSQLENDTRAN= TEXT("SQLEndTran"); 
static LPTSTR szSQLGETCURSORNAME= TEXT("SQLGetCursorName"); 
static LPTSTR szSQLEXECDIRECT= TEXT("SQLExecDirect"); 
static LPTSTR szSQLPUTDATA= TEXT("SQLPutData"); 
static LPTSTR szSQLPARAMDATA= TEXT("SQLParamData"); 
static LPTSTR szSQLROWCOUNT= TEXT("SQLRowCount"); 
static LPTSTR szSQLSETPARAM= TEXT("SQLSetParam"); 
static LPTSTR szSQLBINDPARAMETER= TEXT("SQLBindParameter"); 
static LPTSTR szSQLBINDPARAM= TEXT("SQLBindParam"); 
static LPTSTR szSQLPREPARE= TEXT("SQLPrepare"); 
static LPTSTR szSQLEXECUTE= TEXT("SQLExecute"); 
static LPTSTR szSQLCOLATTRIBUTES= TEXT("SQLColAttributes"); 
static LPTSTR szSQLGETDATA= TEXT("SQLGetData"); 
static LPTSTR szSQLCOLUMNS= TEXT("SQLColumns"); 
static LPTSTR szSQLGETFUNCTIONS= TEXT("SQLGetFunctions");   
static LPTSTR szSQLDRIVERCONNECT= TEXT("SQLDriverConnect"); 
static LPTSTR szSQLDISCONNECT= TEXT("SQLDisconnect"); 
static LPTSTR szSQLCONNECT= TEXT("SQLConnect"); 
static LPTSTR szSQLCANCEL= TEXT("SQLCancel"); 
static LPTSTR szSQLDESCRIBECOL= TEXT("SQLDescribeCol"); 
static LPTSTR szSQLTABLES= TEXT("SQLTables"); 
static LPTSTR szSQLSPECIALCOLUMNS= TEXT("SQLSpecialColumns"); 
static LPTSTR szSQLDESCRIBEPARAM= TEXT("SQLDescribeParam"); 
static LPTSTR szSQLNUMPARAMS= TEXT("SQLNumParams"); 
static LPTSTR szSQLPARAMOPTIONS= TEXT("SQLParamOptions"); 
static LPTSTR szSQLPRIMARYKEYS= TEXT("SQLPrimaryKeys"); 
static LPTSTR szSQLEXTENDEDFETCH= TEXT("SQLExtendedFetch"); 
static LPTSTR szSELECTSTAR= TEXT("select * from %s"); 
static LPTSTR szQUICKREBIND= TEXT("Quick Rebind"); 
static LPTSTR szSQLBROWSECONNECT= TEXT("SQLBrowseConnect"); 
static LPTSTR szBLANKLINE= TEXT(" "); 
static LPTSTR szTAB= TEXT("\t"); 
static LPTSTR szSQLNUMRESULTCOLS= TEXT("SQLNumResultCols"); 
static LPTSTR szSQLSETSCROLLOPTIONS= TEXT("SQLSetScrollOptions"); 
static LPTSTR szSQLFETCHSCROLL= TEXT("SQLFetchScroll"); 
static LPTSTR szSQLSTATISTICS= TEXT("SQLStatistics"); 
static LPTSTR szSQLCLOSECURSOR= TEXT("SQLCloseCursor"); 
static LPTSTR szSQLGETDIAGREC= TEXT("SQLGetDiagRec"); 
static LPTSTR szSQLGETDIAGFIELD= TEXT("SQLGetDiagField"); 
static LPTSTR szRETDATA= TEXT("returned data"); 
static LPTSTR szINCORRECTOUTLEN= TEXT("incorrect outlen"); 
static LPTSTR szSQLNATIVESQL= TEXT("SQLNativeSql"); 
static LPTSTR szSQLNATIVESQLW= TEXT("SQLNativeSqlW"); 
static LPTSTR szSQLCONNECTW= TEXT("SQLConnectW"); 
static LPTSTR szSQLTABLESA= TEXT("SQLTablesA"); 
static LPTSTR szSQLTABLESW= TEXT("SQLTablesW"); 
static LPTSTR szSQLCOLUMNSA= TEXT("SQLColumnsA"); 
static LPTSTR szSQLCOLUMNSW= TEXT("SQLColumnsW"); 
static LPTSTR szSQLEXECDIRECTA= TEXT("SQLExecDirectA"); 
static LPTSTR szSQLEXECDIRECTW= TEXT("SQLExecDirectW"); 
 
LPTSTR iTestNames[]={ 
TEXT("Test Connection Options"), 
TEXT("Test Statement Options"), 
TEXT("Test SQLGetCursorName"), 
TEXT("Test Data"), 
TEXT("Test SQLNumResultCols"), 
TEXT("Test Meta-Data"), 
TEXT("Test Searched Query"), 
TEXT("Test Large Query"), 
TEXT("Test SQLTables"), 
TEXT("Test SQLStatistics"), 
TEXT("Test SQLSpecialColumns"), 
TEXT("Test 'Like' Query"), 
TEXT("Test SQLForeignKeys"), 
TEXT("Test SQLBrowseConnect"), 
TEXT("Test SQLDataSources"), 
TEXT("Test SQLDrivers"), 
TEXT("Test SQLMoreResults"), 
TEXT("Test SQLNativeSQL"), 
TEXT("Test SQLDescribeParam"), 
TEXT("Test SQLNumParams"), 
TEXT("Test SQLParamOptions"), 
TEXT("Test SQLPrimaryKeys"), 
TEXT("Test SQLProcedures"), 
TEXT("Test SQLTablePrivileges"), 
TEXT("Test SQLColumnPrivileges"), 
TEXT("Test SQLSetScrollOptions"), 
TEXT("Test SQLExtendedFetch"), 
TEXT("Test SQL_OJ_CAPABILITIES"), 
TEXT("Test SQLSetConnectAttr"), 
TEXT("Test SQLSetStmtAttr"), 
TEXT("Test Threading"), 
TEXT("Test GetDescField"), 
TEXT("Test SetDescField"), 
TEXT("Test GetDescRec"), 
TEXT("Test SetDescRec"), 
TEXT("Test CopyDesc"), 
TEXT("Test Descriptor Defaults"), 
TEXT("Test Usage of Descriptor"), 
TEXT("Test Environment Attributes"), 
TEXT("Test SQLEndTran"), 
TEXT("Test SQLBindParam"), 
TEXT("Test Quick Rebind"), 
TEXT("Test SQLFetchScroll"), 
TEXT("Test GetDiagRec"), 
TEXT("Test GetDiagField"), 
TEXT("Test MixedAnsiUnicode") 
}; 
 
 
typedef struct tagHANDLES 
{ 
SWORDfHandleType; 
SQLHANDLEhHandle; 
 
} HANDLES, *lpHANDLES; 
 
SUPPORTOPTINFO OptionList[] = {SQL_SO_FORWARD_ONLY, SQL_SCROLL_FORWARD_ONLY, 
SQL_SO_KEYSET_DRIVEN, SQL_SCROLL_KEYSET_DRIVEN, 
SQL_SO_DYNAMIC, SQL_SCROLL_DYNAMIC}; 
 
SUPPORTCONCURINFO ConcurList[] = {SQL_SCCO_READ_ONLY, SQL_CONCUR_READ_ONLY, 
SQL_SCCO_LOCK, SQL_CONCUR_LOCK, 
SQL_SCCO_OPT_TIMESTAMP, SQL_CONCUR_TIMESTAMP, 
SQL_SCCO_OPT_VALUES, SQL_CONCUR_VALUES}; 
 
 
/*--------------------------------------------------------------------------------------*/ 
/* globals */ 
/*--------------------------------------------------------------------------------------*/ 
lpSERVERINFOlpSI = NULL; 
UWORDfBindParameter=FALSE, 
fDiagRecSupported=FALSE, 
fDiagFieldSupported=FALSE, 
uDriverODBCVer=0; 
UWORDguwRowCount=0;// Count of rows in the automaketable 
   
/* these are globals so that the error functions can access them without 
needing to have them passed to every error check */ 
static HENV            henv=SQL_NULL_HENV; 
static HDBC            hdbc=SQL_NULL_HDBC; 
static HSTMT           hstmt=SQL_NULL_HSTMT; 
static SQLHDESC        hdesc=SQL_NULL_HDESC; 
 
 
 
//globals for test descriptors 
TIMESTAMP_STRUCT tsval= {1955, 12, 31, 23, 59, 59, 999}; 
SQLINTEGER cbtsval=sizeof(TIMESTAMP_STRUCT); 
SQLINTEGER cbValueMax, cbValue, swBindOffset=128; 
SQLUINTEGER RowsProcessed; 
SQLSMALLINT DescBuf[MAX_DESC_BUF];  
SQLUSMALLINT StatusArray[STATUS_ARRAY_SIZE]; 
SQLTCHAR buf[MAX_STRING_SIZE]; 
SQLTCHAR szParamName[MAX_STRING_SIZE]=TEXT("Parameter Name"); 
 
struct tagDescType { 
SQLUSMALLINTuwDescType; 
SQLUSMALLINTuwTypeMask; 
TCHAR szDescName[4]; 
} DescTypes[] = { 
SQL_ATTR_APP_ROW_DESC,DESC_ARD,TEXT("ARD"), 
SQL_ATTR_APP_PARAM_DESC,DESC_APD,TEXT("APD"), 
SQL_ATTR_IMP_ROW_DESC,DESC_IRD,TEXT("IRD"), 
SQL_ATTR_IMP_PARAM_DESC,DESC_IPD,TEXT("IPD") 
}; 
 
struct tagDescInfo { 
SQLSMALLINT uwDescField; 
LPTSTR szDescFieldName; 
BOOL fHeader; 
SQLSMALLINT fGettable;// Can be retrieved for given descriptor types 
SQLSMALLINT fSettable;// Can be set for given descriptor types 
SQLSMALLINT fDefault;// Has a default value for the descriptor types 
SQLINTEGER NewValue; 
SQLINTEGER DefaultVal; 
SQLSMALLINT cbValue; 
SQLINTEGER size; 
} rgDescInfo[] ={ 
// Test expects all header fields to be listed first.  The TYPE field must be the first record field listed. 
// size should be set to 0 for string fields, since we don't know up front what to set it to 
// Field IDField NameHeaderGettableSettablefDefaultNew ValueDefault ValueData SizeData Type 
 
//Header fields 
SQL_DESC_COUNT,TEXT("SQL_DESC_COUNT"),TRUE,DESC_ALL,DESC_MOST,DESC_MOST,1,0,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_ALLOC_TYPE,TEXT("SQL_DESC_ALLOC_TYPE"),TRUE,DESC_ALL,DESC_NONE,DESC_ALL,0,SQL_DESC_ALLOC_AUTO,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_ARRAY_SIZE,TEXT("SQL_DESC_ARRAY_SIZE"),TRUE,DESC_AD,DESC_AD,DESC_AD,STATUS_ARRAY_SIZE,1,sizeof(SQLUINTEGER),SQL_IS_UINTEGER, 
SQL_DESC_ARRAY_STATUS_PTR,TEXT("SQL_DESC_ARRAY_STATUS_PTR"),TRUE,DESC_ALL,DESC_ALL,DESC_ALL,(SQLINTEGER)(StatusArray),(SQLINTEGER)NULL,sizeof(SQLPOINTER),SQL_IS_POINTER, 
SQL_DESC_BIND_OFFSET_PTR,TEXT("SQL_DESC_BIND_OFFSET_PTR"),TRUE,DESC_AD,DESC_AD,DESC_AD,(SQLINTEGER)(&swBindOffset),(SQLINTEGER)NULL,sizeof(SQLPOINTER),SQL_IS_POINTER, 
SQL_DESC_BIND_TYPE,TEXT("SQL_DESC_BIND_TYPE"),TRUE,DESC_AD,DESC_AD,DESC_AD,BIND_SIZE,0,sizeof(SQLINTEGER),SQL_IS_INTEGER, 
//SQL_DESC_OUT_OF_LINE_HEAP,TEXT("SQL_DESC_OUT_OF_LINE_HEAP"),TRUE,DESC_AD,DESC_AD,(SQLINTEGER)(StatusArray),sizeof(SQLINTEGER),SQL_IS_POINTER, 
//SQL_DESC_OUT_OF_LINE_HEAP_OCTET_LENGTH,TEXT("SQL_DESC_OUT_OF_LINE_HEAP_OCTET_LENGTH"),TRUE, DESC_AD,DESC_AD,sizeof(StatusArray),sizeof(SQLINTEGER),SQL_IS_NOT_POINTER, 
SQL_DESC_ROWS_PROCESSED_PTR,TEXT("SQL_DESC_ROWS_PROCESSED_PTR"),TRUE,DESC_ID,DESC_ID,DESC_ID,(SQLINTEGER)(&RowsProcessed),(SQLINTEGER)NULL,sizeof(SQLPOINTER),SQL_IS_POINTER, 
 
// Record fields 
SQL_DESC_TYPE,TEXT("SQL_DESC_TYPE"), FALSE,DESC_ALL,DESC_MOST,DESC_AD,SQL_DATETIME,SQL_C_DEFAULT,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_DATETIME_INTERVAL_CODE,TEXT("SQL_DESC_DATETIME_INTERVAL_CODE"),FALSE,DESC_ALL, DESC_MOST,DESC_NONE,SQL_CODE_TIMESTAMP,0,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_CONCISE_TYPE,TEXT("SQL_DESC_CONCISE_TYPE"),FALSE,DESC_ALL,DESC_MOST,DESC_AD,SQL_TYPE_TIMESTAMP,SQL_C_DEFAULT,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_AUTO_UNIQUE_VALUE,TEXT("SQL_DESC_AUTO_UNIQUE_VALUE"),FALSE,DESC_IRD,DESC_NONE,DESC_NONE,0,0,sizeof(SQLINTEGER),SQL_IS_INTEGER, 
//SQL_DESC_BIND_OUT_OF_LINE,TEXT("SQL_DESC_BIND_OUT_OF_LINE"),FALSE,DESC_AD,DESC_AD,SQL_TRUE,sizeof(SQLSMALLINT),SQL_IS_NOT_POINTER, 
SQL_DESC_BASE_COLUMN_NAME,TEXT("SQL_DESC_BASE_COLUMN_NAME"),FALSE,DESC_IRD,DESC_NONE,DESC_NONE,(SQLINTEGER)szParamName,0,sizeof(SQLCHAR),0, 
SQL_DESC_CASE_SENSITIVE,TEXT("SQL_DESC_CASE_SENSITIVE"),FALSE,DESC_ID,DESC_NONE,DESC_NONE,0,0,sizeof(SQLINTEGER),SQL_IS_INTEGER, 
SQL_DESC_CATALOG_NAME,TEXT("SQL_DESC_CATALOG_NAME"),FALSE,DESC_IRD,DESC_NONE,DESC_NONE,(SQLINTEGER)szParamName,0,sizeof(SQLCHAR),0, 
SQL_DESC_DATETIME_INTERVAL_PRECISION, TEXT("SQL_DESC_DATETIME_INTERVAL_PRECISION"),FALSE, DESC_ALL,DESC_MOST,DESC_NONE,3,0,sizeof(SQLINTEGER),SQL_IS_INTEGER, 
SQL_DESC_DISPLAY_SIZE,TEXT("SQL_DESC_DISPLAY_SIZE"),FALSE,DESC_IRD,DESC_NONE, DESC_NONE,0,0,sizeof(SQLINTEGER),SQL_IS_INTEGER, 
SQL_DESC_FIXED_PREC_SCALE,TEXT("SQL_DESC_FIXED_PREC_SCALE"),FALSE,DESC_ID,DESC_NONE,DESC_NONE,0,0,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_LABEL,TEXT("SQL_DESC_LABEL"),FALSE,DESC_IRD,DESC_NONE,DESC_NONE,(SQLINTEGER)szParamName,0,sizeof(SQLCHAR),0, 
SQL_DESC_LENGTH,TEXT("SQL_DESC_LENGTH"),FALSE,DESC_ALL,DESC_MOST,DESC_NONE,23,0,sizeof(SQLUINTEGER),SQL_IS_UINTEGER, 
SQL_DESC_LITERAL_PREFIX,TEXT("SQL_DESC_LITERAL_PREFIX"),FALSE,DESC_IRD,DESC_NONE,DESC_NONE,(SQLINTEGER)szParamName,0,sizeof(SQLCHAR),0, 
SQL_DESC_LITERAL_SUFFIX,TEXT("SQL_DESC_LITERAL_SUFFIX"),FALSE,DESC_IRD,DESC_NONE,DESC_NONE,(SQLINTEGER)szParamName,0,sizeof(SQLCHAR),0, 
SQL_DESC_LOCAL_TYPE_NAME,TEXT("SQL_DESC_LOCAL_TYPE_NAME"),FALSE,DESC_IRD,DESC_NONE,DESC_NONE,(SQLINTEGER)szParamName,0,sizeof(SQLCHAR),0, 
SQL_DESC_NAME,TEXT("SQL_DESC_NAME"),FALSE,DESC_ID,DESC_IPD,DESC_NONE,(SQLINTEGER)szParamName,0,sizeof(SQLCHAR),0, 
SQL_DESC_NULLABLE,TEXT("SQL_DESC_NULLABLE"),FALSE,DESC_ID,DESC_NONE,DESC_NONE,0,0,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_OCTET_LENGTH,TEXT("SQL_DESC_OCTET_LENGTH"),FALSE,DESC_ALL,DESC_MOST,DESC_NONE,sizeof(tsval),0,sizeof(SQLINTEGER),SQL_IS_INTEGER, 
SQL_DESC_OCTET_LENGTH_PTR,TEXT("SQL_DESC_OCTET_LENGTH_PTR"),FALSE,DESC_AD,DESC_AD,DESC_AD,(SQLINTEGER)(&cbtsval),(SQLINTEGER)NULL,sizeof(SQLINTEGER),SQL_IS_POINTER, 
SQL_DESC_PARAMETER_TYPE,TEXT("SQL_DESC_PARAMETER_TYPE"),FALSE,DESC_IPD,DESC_IPD,DESC_IPD,SQL_PARAM_OUTPUT,SQL_PARAM_INPUT,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_PRECISION,TEXT("SQL_DESC_PRECISION"),FALSE,DESC_ALL,DESC_MOST,DESC_NONE,23,0,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_SCALE,TEXT("SQL_DESC_SCALE"),FALSE,DESC_ALL,DESC_MOST,DESC_NONE,3,0,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_SCHEMA_NAME,TEXT("SQL_DESC_SCHEMA_NAME"),FALSE,DESC_IRD,DESC_NONE,DESC_NONE,(SQLINTEGER)szParamName,0,sizeof(SQLCHAR),0, 
SQL_DESC_SEARCHABLE,TEXT("SQL_DESC_SEARCHABLE"),FALSE,DESC_IRD,DESC_NONE,DESC_NONE,0,0,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_TABLE_NAME,TEXT("SQL_DESC_TABLE_NAME"),FALSE,DESC_IRD,DESC_NONE,DESC_NONE,(SQLINTEGER)szParamName,0,sizeof(SQLCHAR),0, 
SQL_DESC_TYPE_NAME,TEXT("SQL_DESC_TYPE_NAME"),FALSE,DESC_ID,DESC_NONE,DESC_NONE,(SQLINTEGER)szParamName,0,sizeof(SQLCHAR),0, 
SQL_DESC_UNSIGNED,TEXT("SQL_DESC_UNSIGNED"),FALSE,DESC_ID,DESC_NONE,DESC_NONE,0,0,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_UPDATABLE,TEXT("SQL_DESC_UPDATABLE"),FALSE,DESC_IRD,DESC_NONE,DESC_NONE,0,0,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_INDICATOR_PTR,TEXT("SQL_DESC_INDICATOR_PTR"),FALSE,DESC_AD,DESC_AD,DESC_AD,SQL_NULL_DATA,(SQLINTEGER)NULL,sizeof(SQLPOINTER),SQL_IS_POINTER, 
SQL_DESC_UNNAMED,TEXT("SQL_DESC_UNNAMED"),FALSE,DESC_ID,DESC_IPD,DESC_NONE,SQL_UNNAMED,SQL_NAMED,sizeof(SQLSMALLINT),SQL_IS_SMALLINT, 
SQL_DESC_DATA_PTR,TEXT("SQL_DESC_DATA_PTR"),FALSE,DESC_AD,DESC_MOST,DESC_AD,(SQLINTEGER)&tsval,(SQLINTEGER)NULL,sizeof(SQLPOINTER),SQL_IS_POINTER 
 }; 
 
struct tagDIAGINFO { 
SQLSMALLINT uwDescField; 
LPTSTR szDescFieldName; 
SWORD irecRecNumber; 
} rgDiagInfo[] ={ 
//SQL_DIAG_CURSOR_ROW_COUNT,TEXT("SQL_DIAG_CURSOR_ROW_COUNT"),0, 
//SQL_DIAG_DYNAMIC_FUNCTION,TEXT("SQL_DIAG_DYNAMIC_FUNCTION"),0, 
//SQL_DIAG_DYNAMIC_FUNCTION_CODE,TEXT("SQL_DIAG_DYNAMIC_FUNCTION_CODE"),0, 
SQL_DIAG_NUMBER,TEXT("SQL_DIAG_NUMBER"),0, 
SQL_DIAG_RETURNCODE,TEXT("SQL_DIAG_RETURNCODE"),0, 
//SQL_DIAG_ROW_NUMBER,TEXT("SQL_DIAG_ROW_NUMBER"),0, 
//SQL_DIAG_COLUMN_NUMBER,TEXT("SQL_DIAG_COLUMN_NUMBER"),1, 
//SQL_DIAG_ROW_COUNT,TEXT("SQL_DIAG_ROW_COUNT"),0, 
SQL_DIAG_SQLSTATE,TEXT("SQL_DIAG_SQLSTATE"),1, 
SQL_DIAG_NATIVE,TEXT("SQL_DIAG_NATIVE"),1, 
SQL_DIAG_MESSAGE_TEXT,TEXT("SQL_DIAG_MESSAGE_TEXT"),1, 
SQL_DIAG_CLASS_ORIGIN,TEXT("SQL_DIAG_CLASS_ORIGIN"),1, 
SQL_DIAG_SUBCLASS_ORIGIN,TEXT("SQL_DIAG_SUBCLASS_ORIGIN"),1, 
//SQL_DIAG_CONNECTION_NAME,TEXT("SQL_DIAG_CONNECTION_NAME"),1, 
SQL_DIAG_SERVER_NAME,TEXT("SQL_DIAG_SERVER_NAME"),1, 
}; 
 
BOOLg_f3XDriver=FALSE; 
 
//the insert statement bufferto hold the insert statement 
TCHAR szInsertStmt[MAX_STRING_SIZE]; 
 
//----------------------------------------------------------------------- 
//      Function:               Supported 
//----------------------------------------------------------------------- 
 
_inline UWORD  PASCAL Supported(UWORD uwSQLFunc) 
{ 
UWORDfLevel2=FALSE; 
RETCODErc=SQL_SUCCESS; 
 
rc = SQLGetFunctions(hdbc, uwSQLFunc,&fLevel2); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETFUNCTIONS); 
 
return(fLevel2); 
 
} //Supported() 
 
 
/*------------------------------------------------------------------------------ 
 *Function:CheckDataResults - To check data returned by Fetch calls  
 *Checks data at (row, col) in result set against (row, col) in table 
 * ----------------------------------------------------------------------------*/ 
BOOL CheckDataResults(SWORD row, SWORD iTableCol, FIELDINFO*  pField, DSTRUCT* pDataStr, 
 SDWORD cbValue, TCHAR* rgbValue) 
{ 
if((pField ->nullable)&& (cbValue<1)) 
{ 
if(cbValue == SQL_NULL_DATA && pDataStr[iTableCol].cb == SQL_NULL_DATA) 
return TRUE; 
return FALSE; 
} 
 
return CmpODBCtoCHAR(pDataStr, rgbValue, pField->wSQLType, iTableCol); 
} 
 
 
/*------------------------------------------------------------------------------ 
/Function:BinToHex 
/Purpose:Render a buffer contents as a hexidecimal string. 
/*----------------------------------------------------------------------------*/ 
 
void PASCAL BinToHex(PTR rgbValue, SWORD cbValue, LPTSTR szHexString) 
{ 
UWORD ib; 
LPTSTR pch; 
TCHAR rgchDigits[] = TEXT("0123456789ABCDEF"); 
 
lstrcpy(szHexString, TEXT("0x")); 
if(cbValue > (MAX_STRING_SIZE - 3)/2 || cbValue < 0) 
cbValue = (MAX_STRING_SIZE - 3)/2; 
 
pch = &szHexString[lstrlen(szHexString)]; 
for(ib=0; ib < cbValue; ib++) 
{ 
*pch++ = rgchDigits[((LPBYTE)rgbValue)[ib] >> 4]; 
*pch++ = rgchDigits[((LPBYTE)rgbValue)[ib] & 0xF]; 
} 
*pch = TEXT('\0'); 
 
} /* BinToHex() */ 
 
 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               SearchForError                           */ 
/*-----------------------------------------------------------------------*/ 
 
_inline int PASCAL SearchForError(HENV henv, HDBC hdbc,HSTMT hstmt,LPTSTR szFindState) 
{ 
TCHAR buf[MAX_STRING_SIZE]; 
RETCODE rc; 
TCHAR szState[6]; 
int found = FALSE; 
 
for(rc = SQLError(henv, hdbc, hstmt, szState, NULL, buf, MAX_STRING_SIZE, NULL) 
; !found && (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) 
; rc = SQLError(henv, NULL, NULL, szState, NULL, buf, MAX_STRING_SIZE, NULL))  
{ 
found = lstrcmp(szState, szFindState) == 0; 
} 
 
return(found); 
 
} /* SearchForError() */ 
 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               szWrite                                  */ 
/*-----------------------------------------------------------------------*/ 
 
_inline VOID WINAPI szWrite(LPTSTR szStr, BOOL fNewLine) 
{ 
szLogPrintf(lpSI, FALSE, szStr); 
if(fNewLine) 
szLogPrintf(lpSI, FALSE, TEXT("\r\n")); 
} 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               GetErrors                         */ 
/*-----------------------------------------------------------------------*/ 
 
VOID PASCAL GetErrors(HENV henv,HDBC hdbc,HSTMT hstmt) 
{ 
TCHAR buf[MAX_ERROR_SIZE]; 
TCHAR largebuf[COMBINED_SIZE]; 
TCHAR szState[100]; 
RETCODE rc=SQL_SUCCESS; 
 
for(rc = SQLError(henv, hdbc, hstmt, szState, NULL, buf, MAX_ERROR_SIZE, NULL) 
; RC_SUCCESSFUL(rc) 
; rc = SQLError(henv, NULL, NULL, szState, NULL, buf, MAX_ERROR_SIZE, NULL)) 
{ 
wsprintf(largebuf,TEXT("\t\t\tState: %s"), szState); 
szWrite(largebuf, TRUE); 
wsprintf(largebuf,TEXT("\t\t\tError: %s"), buf); 
szWrite(largebuf, TRUE); 
} 
 
} /* GetErrors() */ 
 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               GetDiagRecs                         */ 
/*-----------------------------------------------------------------------*/ 
 
VOID PASCAL GetDiagRecs(SWORD fHandleType,SQLHANDLE hHandle) 
{ 
TCHARszMessageText[XLARGEBUFF]=TEXT(""), 
szBuff[XLARGEBUFF]=TEXT(""); 
TCHARszSQLState[100]=TEXT(""); 
RETCODErc=SQL_SUCCESS; 
SWORDirecRecNumber=0; 
SDWORDfNativeError=0; 
SWORDcbBufferLength=sizeof(szMessageText), 
cbTextLength=0; 
SDWORDsdNumRecs=0; 
 
if (fDiagFieldSupported) 
{ 
/* Get number of diag, records */ 
rc = SQLGetDiagField(fHandleType, hHandle,0,SQL_DIAG_NUMBER, 
&sdNumRecs,sizeof(sdNumRecs),NULL); 
} 
 
 
for(irecRecNumber=1;(irecRecNumber <= sdNumRecs) && RC_SUCCESSFUL(rc);irecRecNumber++) 
{ 
rc = SQLGetDiagRec(fHandleType, hHandle, irecRecNumber,szSQLState,&fNativeError, 
szMessageText,cbBufferLength,&cbTextLength); 
 
if (RC_SUCCESSFUL(rc)) 
{ 
wsprintf(szBuff,TEXT("\t\t\tState: %s"), szSQLState); 
szWrite(szBuff, TRUE); 
wsprintf(szBuff,TEXT("\t\t\tError: %s"), szMessageText); 
szWrite(szBuff, TRUE); 
} 
 
} 
 
 
} /* GetErrors() */ 
 
 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               DisplayAllErrors                         */ 
/*-----------------------------------------------------------------------*/ 
 
void  PASCAL DisplayAllErrors() 
{ 
if (!fDiagRecSupported) 
{ 
GetErrors(henv,NULL,NULL); 
GetErrors(NULL,hdbc,NULL); 
GetErrors(NULL,NULL,hstmt); 
} 
else 
{ 
GetDiagRecs(SQL_HANDLE_ENV,henv); 
GetDiagRecs(SQL_HANDLE_DBC,hdbc); 
GetDiagRecs(SQL_HANDLE_STMT,hstmt); 
GetDiagRecs(SQL_HANDLE_DESC,hdesc); 
} 
 
} /* DisplayAllErrors() */ 
 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               RetcodeToTCHAR                            */ 
/*-----------------------------------------------------------------------*/ 
 
LPTSTR  PASCAL RetcodeToTCHAR(RETCODE retcode, LPTSTR buf) 
{ 
switch (retcode)  
{ 
case SQL_SUCCESS: 
lstrcpy (buf,TEXT("SQL_SUCCESS")); 
break; 
case SQL_ERROR: 
lstrcpy (buf,TEXT("SQL_ERROR")); 
break; 
case SQL_SUCCESS_WITH_INFO: 
lstrcpy (buf,TEXT("SQL_SUCCESS_WITH_INFO")); 
break; 
case SQL_NO_DATA_FOUND: 
lstrcpy (buf,TEXT("SQL_NO_DATA_FOUND")); 
break; 
case SQL_NEED_DATA: 
lstrcpy (buf,TEXT("SQL_NEED_DATA")); 
break; 
case SQL_INVALID_HANDLE: 
lstrcpy (buf,TEXT("SQL_INVALID_HANDLE")); 
break; 
case SQL_STILL_EXECUTING: 
lstrcpy (buf,TEXT("SQL_STILL_EXECUTING")); 
break; 
default: 
lstrcpy(buf,TEXT("UNKNOWN rc")); 
} 
 
return buf; 
} 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               ReturnCheck 
//----------------------------------------------------------------------- 
 
int  PASCAL ReturnCheck(RETCODE retExpected, RETCODE retReceived, LPTSTR szFunction,  
LPTSTR szFile, int iLine,BOOL fDiag) 
{ 
TCHAR buf[MAX_STRING_SIZE]; 
 
if(retExpected == retReceived) 
return TRUE; 
 
szWrite(TEXT(""), TRUE); 
 
szWrite(TEXT("\t\t\t"), FALSE); 
szWrite(szFunction, TRUE); 
 
szWrite(TEXT("\t\t\tExpected: "), FALSE); 
szWrite(RetcodeToTCHAR(retExpected, buf), TRUE); 
 
szWrite(TEXT("\t\t\tReceived: "), FALSE); 
szWrite(RetcodeToTCHAR(retReceived, buf), TRUE); 
 
if (!fDiag) 
DisplayAllErrors(); 
 
wsprintf(buf,TEXT("\t\t\t%s: %d"), szFile, iLine); 
szWrite(buf, TRUE); 
 
szWrite(TEXT("\t\t\t --------  "), TRUE); 
 
lpSI->failed++; 
 
return FALSE; 
} 
 
//----------------------------------------------------------------------- 
//      Function:               ErrsHandle 
//----------------------------------------------------------------------- 
 
int  PASCAL ErrsHandle(SWORD fHandleType,SQLHANDLE hHandle, RETCODE retExpected, 
RETCODE retReceived, LPTSTR szFunction, LPTSTR szFile, int iLine,BOOL fDiag) 
{ 
TCHAR buf[MAX_STRING_SIZE]; 
 
if(retExpected == retReceived) 
return TRUE; 
 
szWrite(TEXT(""), TRUE); 
 
szWrite(TEXT("\t\t\t"), FALSE); 
szWrite(szFunction, TRUE); 
 
szWrite(TEXT("\t\t\tExpected: "), FALSE); 
szWrite(RetcodeToTCHAR(retExpected, buf), TRUE); 
 
szWrite(TEXT("\t\t\tReceived: "), FALSE); 
szWrite(RetcodeToTCHAR(retReceived, buf), TRUE); 
 
if (!fDiag) 
GetDiagRecs(fHandleType,hHandle); 
 
wsprintf(buf,TEXT("\t\t\t%s: %d"), szFile, iLine); 
szWrite(buf, TRUE); 
 
szWrite(TEXT("\t\t\t --------  "), TRUE); 
 
lpSI->failed++; 
 
return FALSE; 
} 
 
/*------------------------------------------------------------------------------ 
/Function:FindError 
/Purpose:Find the expected error message. Display a failure if not found. 
/*----------------------------------------------------------------------------*/ 
 
BOOL PASCAL FindError(SWORD fHandleType, LPTSTR szFindState) 
{ 
SQLHANDLE handle = SQL_NULL_HANDLE; 
SWORD irec; 
TCHAR szErrorMsg[SQL_MAX_MESSAGE_LENGTH]; 
RETCODE rc; 
TCHAR szState[6]; 
 
switch(fHandleType) 
{ 
case SQL_HANDLE_ENV: 
handle = henv; 
break; 
 
case SQL_HANDLE_DBC: 
handle = hdbc; 
break; 
 
case SQL_HANDLE_STMT: 
handle = hstmt; 
break; 
 
case SQL_HANDLE_DESC: 
if(!Supported(SQL_API_SQLGETDIAGREC)) 
return TRUE; 
 
handle = hdesc; 
break; 
 
default: 
DISPLAYERROR(TEXT("FindError"), TEXT("invalid fHandleType")); 
return FALSE; 
} 
 
for(irec = 1 
; rc = SQLGetDiagRec(fHandleType, handle, irec, szState, NULL, szErrorMsg, SQL_MAX_MESSAGE_LENGTH, NULL) 
, RC_SUCCESSFUL(rc) 
; irec++) 
{ 
if(lstrcmp(szState, szFindState) == 0) 
return TRUE; 
} 
return FALSE; 
 
} /* FindError() */ 
 
/*------------------------------------------------------------------------------ 
 *Function:CompareWithExpected 
 *Checks data in rgbValue against expected value given row, col, and rgFields. 
 *Posts an error if mismatch 
 * ----------------------------------------------------------------------------*/ 
void CompareWithExpected(PTR rgbValue, SDWORD * pcbValue, UWORD row, UWORD icol, FIELDINFO  *rgFields) 
{ 
LPTSTR   pch=NULL; 
TCHAR szExpBuf[MAX_STRING_SIZE]=TEXT(""); 
TCHAR * stopstr; 
 
pch = qtMakeData(row-1, icol-1, &rgFields[icol-1], szExpBuf); 
 
// Field is not READ ONLY, compare the value we inserted 
if(pch)  
{ 
 // Where row and column match and field is nullable, a NULL exists 
if (icol-1 == row-1 && rgFields[icol-1].nullable) 
{ 
// Post an error if not SQL_NULL_DATA 
if (*pcbValue != SQL_NULL_DATA) 
DISPLAYERROR(TEXT("Simulate BindCol"),TEXT("Didn't return SQL_NULL_DATA")); 
} 
else 
{ 
BOOL bCompare; 
TCHAR * pstr=szExpBuf;// Pointer to start of expected string 
 
switch(rgFields[icol-1].wSQLType) 
{ 
case SQL_BIT: 
case SQL_TINYINT: 
case SQL_SMALLINT: 
case SQL_INTEGER: 
// Compare the data values as long // tcsncmp 
bCompare=(_ttol(rgbValue) == _ttol(pstr)); 
break; 
case SQL_NUMERIC: 
case SQL_DECIMAL: 
case SQL_FLOAT: 
case SQL_REAL: 
case SQL_DOUBLE: 
// Compare the data values as doubles strtod 
bCompare=(_tcstod(rgbValue, &stopstr) == _tcstod(pstr, &stopstr)); 
break; 
case SQL_DATE: 
case SQL_TIME: 
case SQL_TIMESTAMP: 
case SQL_TYPE_DATE: 
case SQL_TYPE_TIME: 
case SQL_TYPE_TIMESTAMP: 
pstr=szExpBuf+lstrlen(TEXT("{ts '")); 
// Replace second ' with '\0'' 
_tcstok(pstr, TEXT("'")); 
if (lstrlen(rgbValue) > lstrlen(TEXT("1994-10-10 10:00:00"))) 
lstrcat(pstr, TEXT(".000")); 
bCompare=(!_tcsncmp(rgbValue, pstr, rgFields[icol-1].precision)); 
break; 
default: 
bCompare=(!_tcsncmp(rgbValue, pstr, lstrlen(pstr))); 
} 
 
// Compare the data values as char  
if (!bCompare) 
{ 
DISPLAYERROR(TEXT("Simulate BindCol"),TEXT("Returned data didn't match")); 
szWrite(TEXT("\t\t\tExpected: "), FALSE); 
szWrite(pstr, TRUE); 
szWrite(TEXT("\t\t\tReceived: "), FALSE); 
szWrite(rgbValue, TRUE); 
} 
} 
} 
} //CompareWithExpected 
 
//----------------------------------------------------------------------- 
//      Function:               ResetHstmt 
//----------------------------------------------------------------------- 
void ResetHstmt(SQLHSTMT * phstmt) 
{ 
SQLRETURN rc; 
 
// Free and reallocate stmt handle to clean up 
rc=SQLFreeHandle(SQL_HANDLE_STMT, *phstmt); 
ERRSHANDLE(SQL_HANDLE_STMT, *phstmt, SQL_SUCCESS, rc, szSQLFREESTMT); 
rc=SQLAllocHandle(SQL_HANDLE_STMT, hdbc, phstmt); 
RETCHECK(SQL_SUCCESS, rc,szSQLALLOCHANDLE); 
} 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               GetSomeData                              */ 
/*-----------------------------------------------------------------------*/ 
 
VOID PASCAL GetSomeData(HSTMT lhstmt, LPTSTR szTableName,BOOL fBindCol, 
FIELDINFO  rgField) 
{ 
RETCODErc=SQL_SUCCESS; 
SDWORDcbValue=0; 
TCHARszQuery[XLARGEBUFF]=TEXT(""), 
szBuff[XLARGEBUFF]=TEXT(""); 
TCHARszErrMsg[MAX_STRING_SIZE]=TEXT(""), 
szDataItem[XLARGEBUFF]=TEXT(""); 
LPTSTR   pch=NULL; 
 
pch = qtMakeData(0, 0,&rgField, szDataItem); 
 
wsprintf(szQuery,szSELECTSTAR,szTableName); 
rc=SQLExecDirect(lhstmt,szQuery,SQL_NTS); 
//RETCHECK(SQL_SUCCESS,rc,szSQLEXECDIRECT); 
 
if (fBindCol) 
{ 
rc = SQLBindCol(lhstmt, 1, SQL_C_TCHAR, szBuff, sizeof(szBuff),&cbValue); 
//RETCHECK(SQL_SUCCESS, rc, szSQLBINDCOL); 
} 
 
rc = SQLFetch(lhstmt); 
//RETCHECK(SQL_SUCCESS, rc,szSQLFETCH); 
 
if (!fBindCol) 
{ 
rc = SQLGetData(lhstmt,1, SQL_C_TCHAR,szBuff, sizeof(szBuff), NULL); 
//RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); 
} 
 
lstrcmp(szDataItem,szBuff); 
 
} /* GetSomeData() */ 
 
 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               SelectFromTable                          */ 
/*-----------------------------------------------------------------------*/ 
 
_inline RETCODE PASCAL SelectFromTable(QTSTRUCT *lpqt) 
{ 
RETCODErc=SQL_SUCCESS; 
TCHARszQuery[LARGEBUFF]; 
 
wsprintf(szQuery,TEXT("select %s from %s"),  
//wsprintf(szQuery,TEXT("select %s from %s order by %s"),  
lpqt->szColNames, lpqt->szTableName/*, lpqt->szColNames*/); 
 
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
return(rc); 
 
} /* SelectFromTable() */ 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               SelectFromTableFetch                     */ 
/*-----------------------------------------------------------------------*/ 
 
_inline RETCODE PASCAL SelectFromTableFetch(QTSTRUCT *lpqt, TCHAR* szColName) 
{ 
RETCODErc=SQL_SUCCESS; 
TCHARszQuery[LARGEBUFF]; 
 
wsprintf(szQuery,TEXT("select %s from %s order by %s"),  
lpqt->szColNames, lpqt->szTableName, szColName); 
 
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); 
if((SQL_SUCCESS!=rc) && (SQL_SUCCESS_WITH_INFO!=rc)){ 
RETCHECK(SQL_SUCCESS_WITH_INFO, rc,szSQLEXECDIRECT); 
return SQL_NO_DATA; 
} 
 
return SQL_SUCCESS; 
} /* SelectFromTableFetch() */ 
 
//----------------------------------------------------------------------- 
//      Function:               AllocHstmt 
//----------------------------------------------------------------------- 
 
_inline BOOL PASCAL AllocHstmt() 
{ 
BOOLfFailed=FALSE; 
RETCODErc=SQL_SUCCESS; 
 
if (Supported(SQL_API_SQLALLOCHANDLE)) 
{ 
rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt); 
if(!RETCHECK(SQL_SUCCESS, rc, szSQLALLOCHANDLE)) 
fFailed=TRUE; 
} 
else 
{ 
rc = SQLAllocStmt(hdbc, &hstmt); 
if(!RETCHECK(SQL_SUCCESS, rc, szSQLALLOCSTMT)) 
fFailed=TRUE; 
} 
 
 
return(fFailed); 
 
} //AllocHstmt() 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               AllocHdbc 
//----------------------------------------------------------------------- 
 
_inline BOOL PASCAL AllocHdbc(HDBC *phdbc) 
{ 
BOOLfFailed=FALSE; 
RETCODErc=SQL_SUCCESS; 
 
if (Supported(SQL_API_SQLALLOCHANDLE)) 
{ 
rc = SQLAllocHandle(SQL_HANDLE_DBC,henv, phdbc); 
if(!RETCHECK(SQL_SUCCESS, rc, szSQLALLOCHANDLE)) 
fFailed=TRUE; 
} 
else 
{ 
rc = SQLAllocConnect(henv, phdbc); 
if(!RETCHECK(SQL_SUCCESS, rc, szSQLALLOCCONNECT)) 
fFailed=TRUE; 
} 
 
 
return(fFailed); 
 
} //AllocHdbc() 
 
 
//----------------------------------------------------------------------- 
//      Function:AllocHenv 
//----------------------------------------------------------------------- 
 
_inline BOOL PASCAL PASCAL AllocHenv() 
{ 
BOOLfFailed=FALSE; 
RETCODErc=SQL_SUCCESS; 
 
rc = SQLAllocEnv(&henv); 
if (!RETCHECK(SQL_SUCCESS, rc,szSQLALLOCENV)) 
fFailed=TRUE; 
 
return(fFailed); 
 
} //AllocHenv() 
 
//----------------------------------------------------------------------- 
//      Function:               SetStatementAttributes 
//----------------------------------------------------------------------- 
 
_inline BOOL PASCAL SetStatementAttributes(UWORD fAttr, PTR rgbValue) 
{ 
RETCODErc=SQL_SUCCESS; 
TCHARszAPI[MEDBUFF]; 
BOOLfFailed=FALSE; 
 
if (Supported(SQL_API_SQLSETSTMTATTR)) 
{ 
rc = SQLSetStmtAttr(hstmt,(SDWORD)fAttr,rgbValue,sizeof(UDWORD)); 
lstrcpy(szAPI,szSQLSETSTMTATTR); 
} 
else 
{ 
rc = SQLSetStmtOption(hstmt,fAttr,(UDWORD)rgbValue); 
lstrcpy(szAPI,szSQLSETSTMTOPTION); 
} 
 
if (rc != SQL_SUCCESS) 
{ 
if(!FindError(SQL_HANDLE_STMT,szHYC00)) 
RETCHECK(SQL_SUCCESS, rc,szAPI); 
 
fFailed=TRUE; 
} 
 
return(fFailed); 
 
} //SetStatementAttributes() 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               SetConnectionAttributes 
//----------------------------------------------------------------------- 
 
_inline BOOL PASCAL SetConnectionAttributes(HDBC lhdbc,UWORD fAttr, UDWORD rgbValue) 
{ 
RETCODErc=SQL_SUCCESS; 
TCHARszAPI[MEDBUFF]; 
BOOLfFailed=FALSE; 
 
if (Supported(SQL_API_SQLSETCONNECTATTR)) 
{ 
rc = SQLSetConnectAttr(lhdbc,(SDWORD)fAttr,(PTR)rgbValue,sizeof(UDWORD)); 
lstrcpy(szAPI,szSQLSETCONNECTATTR); 
} 
else 
{ 
rc = SQLSetConnectOption(lhdbc,fAttr,rgbValue); 
lstrcpy(szAPI,szSQLSETCONNECTOPTION); 
} 
 
if (rc != SQL_SUCCESS) 
{ 
if(!FindError(SQL_HANDLE_DBC,szHYC00)) 
RETCHECK(SQL_SUCCESS, rc,szAPI); 
 
fFailed=TRUE; 
} 
 
return(fFailed); 
 
} //SetConnectionAttributes() 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               FreeStmt 
//----------------------------------------------------------------------- 
 
_inline BOOL PASCAL FreeStmt(UWORD fOption) 
{ 
RETCODErc=SQL_SUCCESS; 
 
if (Supported(SQL_API_SQLFREEHANDLE) && (fOption == SQL_DROP)) 
{ 
rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE); 
} 
else 
{ 
rc = SQLFreeStmt(hstmt, fOption); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT); 
} 
 
return(RC_NOTSUCCESSFUL(rc)); 
 
} //FreeStmt() 
 
//----------------------------------------------------------------------- 
//      Function:               DropHdbc 
//----------------------------------------------------------------------- 
 
VOID PASCAL DropHdbc(HDBC hdbc) 
{ 
RETCODE rc=SQL_SUCCESS; 
 
if (Supported(SQL_API_SQLFREEHANDLE)) 
{ 
rc = SQLFreeHandle(SQL_HANDLE_DBC,hdbc); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE); 
} 
else 
{ 
rc = SQLFreeConnect(hdbc); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREECONNECT); 
} 
 
} //DropHdbc() 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               DropHenv 
//----------------------------------------------------------------------- 
 
_inline VOID PASCAL DropHenv() 
{ 
RETCODE rc=SQL_SUCCESS; 
 
if (Supported(SQL_API_SQLFREEHANDLE)) 
{ 
rc = SQLFreeHandle(SQL_HANDLE_ENV,henv); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE); 
} 
else 
{ 
rc = SQLFreeEnv(henv); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREEENV); 
} 
 
} //DropHenv() 
 
 
//----------------------------------------------------------------------- 
//      Function:               ClearErrorQueue 
//----------------------------------------------------------------------- 
 
VOID PASCAL ClearErrorQueue() 
{ 
TCHAR szErrMsg[MAX_STRING_SIZE]; 
TCHAR szState[6]; 
 
/* Eat up the SQL_SUCCESS_WITH_INFO error record */ 
while (RC_SUCCESSFUL(SQLError(NULL, hdbc,NULL, szState, NULL,  
szErrMsg, sizeof(szErrMsg), NULL))) 
; 
} 
 
 
//----------------------------------------------------------------------- 
//      Function:               Is3XDriver 
//----------------------------------------------------------------------- 
 
BOOL PASCAL Is3XDriver(HDBC hdbc,QTSTRUCT *lpqt) 
{ 
RETCODErc=SQL_SUCCESS; 
LPTSTRpch=NULL; 
BOOLf3XDriver=FALSE; 
 
rc = SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, lpqt->buf, MAX_STRING_SIZE, NULL); 
if(RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO)) 
{ 
pch = _tcstok(lpqt->buf,TEXT(".")); 
 
if (!_tcsnccmp(pch,TEXT("02"), 2)) 
{ 
pch = _tcstok(NULL,TEXT(".")); 
 
if(!_tcsnccmp(pch,TEXT("00"), 2)) 
DISPLAYERROR(szSQLGETINFO,TEXT("Driver returned ODBC version 2.00 which is no longer supported.  Please upgrade to 2.01")); 
 
} 
else if (!_tcsnccmp(pch,TEXT("03"), 2)) 
f3XDriver=TRUE; 
} 
 
uDriverODBCVer=_ttoi(lpqt->buf); 
 
return(f3XDriver); 
 
} //Is3XDriver() 
 
 
//----------------------------------------------------------------------- 
//      Function:               Connect 
//----------------------------------------------------------------------- 
 
BOOL  PASCAL Connect(lpSERVERINFO lpSI,QTSTRUCT  *lpqt) 
{ 
RETCODErc=SQL_SUCCESS; 
SDWORD sdwAppVer; 
 
/* The signal for test to use it's 
own allocated handles, is if the a server name is passed in.  If it 
is not, the test should use the hdbc passed in */ 
 
/* ****************** Allocate Env ************************* */ 
if (AllocHenv()) 
goto ConnectErrorRet; 
 
/* ****************** Set Application Version ************************* */ 
rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 
SQL_IS_UINTEGER); 
if(!RETCHECK(SQL_SUCCESS, rc, szSQLSETENVATTR)) 
goto ConnectErrorRet; 
 
/* ****************** Allocate Connection ************************* */ 
 
rc = SQLAllocConnect(henv, &hdbc); 
if(!RETCHECK(SQL_SUCCESS, rc, szSQLALLOCCONNECT)) 
goto ConnectErrorRet; 
 
/* ****************** Set Connection Attributes ************************* */ 
rc = SQLSetConnectOption(hdbc,SQL_ODBC_CURSORS,lpSI->vCursorLib); 
 
if(!FindError(SQL_HANDLE_DBC,szHYC00)) 
if (!RETCHECK(SQL_SUCCESS, rc,szSQLSETCONNECTOPTION)) 
goto ConnectErrorRet; 
 
/* create a DriverConnect string */ 
wsprintf(lpqt->sz, TEXT("dsn=%s;uid=%s;pwd=%s;"), 
lpSI->szValidServer0, 
lpSI->szValidLogin0, 
lpSI->szValidPassword0); 
 
/* since SQL_DRIVER_COMPLETE is used, it is possible that the 
driver will bring up a dialog asking for more information. */ 
rc = SQLDriverConnect(hdbc, lpSI->hwnd, lpqt->sz, 
SQL_NTS, lpqt->buf, MAX_STRING_SIZE, NULL, SQL_DRIVER_COMPLETE); 
 
if (RC_NOTSUCCESSFUL(rc)) 
{ 
if (!RETCHECK(SQL_SUCCESS, rc,szSQLDRIVERCONNECT)) 
goto ConnectErrorRet; 
} 
else 
ClearErrorQueue(); 
 
 
rc = SQLDisconnect(hdbc); 
RETCHECK(SQL_SUCCESS, rc,szSQLDISCONNECT); 
 
rc = SQLConnect(hdbc, lpSI->szValidServer0, SQL_NTS, 
lpSI->szValidLogin0, SQL_NTS, 
lpSI->szValidPassword0, SQL_NTS); 
 
if (RC_SUCCESSFUL(rc)) 
ClearErrorQueue(); 
else if (!RETCHECK(SQL_SUCCESS, rc,szSQLCONNECT)) 
goto ConnectErrorRet; 
 
// Set the global 3.0 driver flag 
g_f3XDriver=Is3XDriver(hdbc,lpqt); 
 
// We're now connected, check application version and adjust expected error 
// states appropriately. 
rc = SQLGetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, &sdwAppVer, SQL_IS_UINTEGER, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETENVATTR); 
 
if (RC_SUCCESSFUL(rc) && (SQL_OV_ODBC2 == sdwAppVer)) 
{ 
lstrcpy(szHY009, TEXT("S1009")); 
lstrcpy(szHYC00, TEXT("S1C00")); 
} 
 
return(FALSE); 
 
ConnectErrorRet: 
 
return(TRUE); 
 
} //Connect() 
 
 
//----------------------------------------------------------------------- 
//      Function:               IgnoreType 
//----------------------------------------------------------------------- 
 
BOOL  PASCAL IgnoreType(LPTSTR szType,SWORD wSQLType) 
{ 
BOOL fIgnore=FALSE; 
 
/* If a line below is compiled in, that type will not be used in creating 
 the table.  (useful for when one specific type is causing problems in 
 a particular test, this way the test can be run for all other types) 
*/ 
 
if (!lstrcmp(szType,TEXT("LONG RAW")) || 
 !lstrcmp(szType,TEXT("LONG VARTCHAR")) || 
  !lstrcmp(szType,TEXT("LONG VARTCHAR FOR BIT DATA"))) 
{ 
 fIgnore=TRUE; 
} 
 
//if (wSQLType != SQL_CHAR) 
//fIgnore=TRUE; 
 
return(fIgnore); 
 
} //IgnoreType() 
 
 
//----------------------------------------------------------------------- 
//      Function:               CheckConformanceLevel 
//----------------------------------------------------------------------- 
 
UWORD  PASCAL CheckConformanceLevel() 
{ 
RETCODE rc=SQL_SUCCESS; 
UWORDfIndex=0; 
SWORDcb=0; 
 
rc = SQLGetInfo(hdbc, SQL_ODBC_SQL_CONFORMANCE, &fIndex, 
sizeof (fIndex), &cb); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); 
 
if(fIndex != 0 && fIndex != 1 && fIndex != 2) { 
/* one of these two values should always be returned */ 
DISPLAYERROR(szSQLGETINFO,TEXT("SQL_ODBC_API_CONFORMANCE - invalid value")); 
} 
 
return(fIndex); 
 
} //CheckConformanceLevel() 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               TestConnectionOptions */ 
/*-----------------------------------------------------------------------*/ 
 
void  PASCAL TestConnectionOptions() 
{ 
RETCODErc=SQL_SUCCESS; 
SDWORDsdw, 
cbValue=0; 
BOOLfConnectOption=TRUE; 
TCHARszAPI[MEDBUFF]; 
HDBClhdbc=NULL; 
 
 
rc=SQLAllocConnect(henv,&lhdbc); 
RETCHECK(SQL_SUCCESS, rc,szSQLALLOCCONNECT); 
 
SetConnectionAttributes(lhdbc,SQL_ACCESS_MODE,SQL_MODE_READ_WRITE); 
 
SetConnectionAttributes(lhdbc,SQL_AUTOCOMMIT,TRUE); 
 
if (SetConnectionAttributes(lhdbc,SQL_LOGIN_TIMEOUT,TEST_CONNECT_OPTION)) 
fConnectOption = FALSE; 
 
if (Supported(SQL_API_SQLGETCONNECTATTR)) 
{ 
rc = SQLGetConnectAttr(lhdbc, SQL_LOGIN_TIMEOUT, (PTR)&sdw,0,&cbValue); 
lstrcpy(szAPI,szSQLGETCONNECTATTR); 
} 
else 
{ 
rc = SQLGetConnectOption(lhdbc, SQL_LOGIN_TIMEOUT, &sdw); 
lstrcpy(szAPI,szSQLSETCONNECTOPTION); 
} 
 
 
if(rc != SQL_SUCCESS) 
{ 
if(!FindError(SQL_HANDLE_DBC,szHYC00)) 
RETCHECK(SQL_SUCCESS, rc,szAPI); 
} 
else 
{ 
if(sdw != TEST_CONNECT_OPTION && fConnectOption) 
DISPLAYERROR(szAPI,TEXT("SQL_LOGIN_TIMEOUT returned incorrect value")); 
} 
 
rc=SQLFreeConnect(lhdbc); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREECONNECT); 
 
} //TestConnectionOptions() 
 
 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:            CanAllocHdesc        */ 
/*-----------------------------------------------------------------------*/ 
 
BOOL PASCAL CanAllocHdesc() 
{ 
BOOL fSupported=FALSE; 
 
/* Allocate an hdesc: */ 
if(Supported(SQL_API_SQLALLOCHANDLE)) 
fSupported = RC_SUCCESSFUL(SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc)); 
 
return(fSupported); 
 
} 
 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:            SetErrorCondition    */ 
/*-----------------------------------------------------------------------*/ 
 
VOID PASCAL SetErrorCondition(SWORD fHandleType) 
{ 
RETCODE rc=SQL_SUCCESS; 
 
/* The following are used to produce "(S1)HY009" SQL State */ 
switch (fHandleType) 
{ 
case SQL_HANDLE_ENV: 
rc = SQLAllocConnect(henv, NULL); 
break; 
case SQL_HANDLE_DBC: 
rc = SQLAllocStmt(hdbc, NULL); 
break; 
case SQL_HANDLE_STMT: 
rc = SQLExecDirect(hstmt, NULL, SQL_NTS);// Produces a DM error 
break; 
case SQL_HANDLE_DESC: 
rc = SQLGetDescField(hdesc, 0, SQL_DESC_AUTO_UNIQUE_VALUE, NULL, 0, NULL); 
break; 
} 
 
} //SetErrorCondition() 
 
 
 
VOID PASCAL CheckData(SWORD fHandleType,UWORD uwDescField, PTR rgbValue,LPTSTR szDataSourceName) 
{ 
TCHARszBuff[MEDBUFF]=TEXT(""); 
LPTSTRpszExpState=szHY009; 
 
if (fHandleType == SQL_HANDLE_DESC) 
pszExpState=szHY091; 
 
switch(uwDescField) 
{ 
case SQL_DIAG_RETURNCODE: 
{ 
RETCODE rcRec=*(RETCODE *)rgbValue; 
 
if (rcRec!= SQL_ERROR) 
{ 
wsprintf(szBuff,TEXT("\t\t\tSQL_DIAG_RETURN_CODE\tReceived: %d\tExpected: %d"),rcRec,-1); 
} 
} 
break; 
 
case SQL_DIAG_SQLSTATE: 
{ 
if (lstrcmp((LPTSTR)rgbValue,pszExpState)) 
{ 
wsprintf(szBuff,TEXT("\t\t\tSQL_DIAG_SQLSTATE\tReceived: %s\tExpected: %s"),(LPTSTR)rgbValue,pszExpState); 
} 
} 
break; 
case SQL_DIAG_CLASS_ORIGIN: 
{ 
if (lstrcmp((LPTSTR)rgbValue,szISO)) 
wsprintf(szBuff,TEXT("\t\t\tSQL_DIAG_CLASS_ORIGIN\tReceived: %s\tExpected: %s"),(LPTSTR)rgbValue,szISO); 
} 
break; 
case SQL_DIAG_SUBCLASS_ORIGIN: 
{ 
if (lstrcmp((LPTSTR)rgbValue,szISO)) 
wsprintf(szBuff,TEXT("\t\t\tSQL_DIAG_CLASS_ORIGIN\tReceived: %s\tExpected: %s"),(LPTSTR)rgbValue,szISO); 
} 
break; 
case SQL_DIAG_NUMBER: 
{ 
SDWORD cRecs=*(SDWORD *)rgbValue; 
if (cRecs != 1) 
wsprintf(szBuff,TEXT("\t\t\tSQL_DIAG_NUMBER\tReceived: %d\tExpected: %d"),cRecs,1); 
} 
break; 
case SQL_DIAG_SERVER_NAME: 
{ 
switch(fHandleType) 
{ 
case SQL_HANDLE_DBC: 
case SQL_HANDLE_STMT: 
if (lstrcmp((LPTSTR)rgbValue,szDataSourceName)) 
wsprintf(szBuff,TEXT("\t\t\tSQL_DIAG_SERVER_NAME\tReceived: %s\tExpected: %s"),(LPTSTR)rgbValue,szDataSourceName); 
break; 
} 
} 
break; 
default: 
break; 
 
} 
 
if (*szBuff) 
DISPLAYERROR(szSQLGETDIAGREC,szBuff); 
 
} /* CheckData() */ 
 
 
/*------------------------------------------------------------------------------ 
/Function:TestDiagRec                                               
/Purpose:For each type of handle, generate an error. If SQLGetDiagField       
/is not supported, verify the appropriate DM error is returned.       
/Otherwise, verify SQLGetDiagField returns the expected error         
/information. If SQLGetDiagRec is not supported, verify the           
/appropriate DM error is returned. Otherwise, verify                  
/SQLGetDiagField returns the expected error information. If           
/SQLGetDiagRec is supported, compare its output with that of          
/SQLGetDiagField.                                                     
/*----------------------------------------------------------------------------*/ 
 
void PASCAL TestDiagRec() 
{ 
SQLRETURNrcFunction,  
rc=SQL_SUCCESS; 
SWORDcbErrorMsg; 
SDWORDfNativeError; 
UWORDiHandle=0, 
iField=0, 
cHandles; 
 
SDWORD*pfNativeError = NULL; 
LPTSTRpchMessageText = NULL; 
 
TCHARszDataSourceName[MAX_STRING_SIZE] = TEXT(""); 
TCHARszState[SQL_SQLSTATE_SIZE+1]; 
TCHARszErrorMsg[SQL_MAX_MESSAGE_LENGTH]; 
TCHARszAPI[MEDBUFF]=TEXT(""); 
TCHARszBuff[MEDBUFF]=TEXT(""); 
 
LPTSTRpszExpState=szHY009; 
RETCODErcExp=SQL_SUCCESS; 
 
HANDLES rgHandles[] =  
{ 
SQL_HANDLE_ENV, henv, 
SQL_HANDLE_DBC, hdbc, 
SQL_HANDLE_STMT, hstmt, 
SQL_HANDLE_DESC, hdesc, 
}; 
 
cHandles=sizeof(rgHandles)/sizeof(HANDLES); 
 
/* Call SQLGetInfo to get values to compare: */ 
rcFunction = SQLGetInfo(hdbc, SQL_DATA_SOURCE_NAME, szDataSourceName, MAX_STRING_SIZE, NULL); 
RETCHECK(SQL_SUCCESS, rcFunction, szSQLGETINFO); 
 
/* Allocate an hdesc: */ 
if(Supported(SQL_API_SQLALLOCHANDLE) && g_f3XDriver) 
{  
rcFunction = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc); 
RETCHECK(SQL_SUCCESS, rcFunction, szSQLALLOCHANDLE); 
 
// Update the array entry for the hdesc 
rgHandles[3].hHandle=hdesc; 
 
} 
else 
cHandles--; 
 
for (iHandle=0; iHandle < cHandles; iHandle++) 
{ 
 
SetErrorCondition(rgHandles[iHandle].fHandleType); 
 
rc = SQLGetDiagRec(rgHandles[iHandle].fHandleType, rgHandles[iHandle].hHandle,  
1,szState,&fNativeError, szErrorMsg, 
SQL_MAX_MESSAGE_LENGTH, &cbErrorMsg); 
 
if (rgHandles[iHandle].fHandleType == SQL_HANDLE_DESC) 
pszExpState=szHY091; 
 
rcExp=SQL_SUCCESS; 
 
if(fDiagRecSupported) 
{ 
 
DIAGRETCHECK(rcExp, rc, szSQLGETDIAGREC); 
if (RC_SUCCESSFUL(rc) && lstrcmp(szState,pszExpState)) 
{ 
wsprintf(szBuff,TEXT("\t\t\tReceived: %s\tExpected: %s"),szState,pszExpState); 
DISPLAYERROR(szSQLGETDIAGREC,szBuff); 
} 
} 
else 
{ 
if(!FindError(rgHandles[iHandle].fHandleType, szIM001)) 
DISPLAYERROR(szSQLGETDIAGREC, szNotSupported); 
} 
 
} 
 
 
/* Free the hdesc: */ 
if (hdesc) 
{ 
rcFunction = SQLFreeHandle(SQL_HANDLE_DESC, hdesc); 
RETCHECK(rcExp, rcFunction, szSQLFREEHANDLE); 
hdesc = SQL_NULL_HDESC; 
} 
 
//ExitTestDiagRec 
 
FreeStmt(SQL_CLOSE); 
 
} /* TestDiagRec() */ 
 
 
/*------------------------------------------------------------------------------ 
/Function:TestDiagField                                                
/Purpose:For each type of handle, generate an error. If SQLGetDiagField       
/is not supported, verify the appropriate DM error is returned.       
/Otherwise, verify SQLGetDiagField returns the expected error         
/information. If SQLGetDiagRec is not supported, verify the           
/appropriate DM error is returned. Otherwise, verify                  
/SQLGetDiagField returns the expected error information. If           
/SQLGetDiagRec is supported, compare its output with that of          
/SQLGetDiagField.                                                     
/*----------------------------------------------------------------------------*/ 
 
void PASCAL TestDiagField() 
{ 
SQLRETURNrcFunction,  
rc=SQL_SUCCESS; 
SWORDcbValue=0; 
UWORDiHandle=0, 
iField=0, 
cHandles; 
 
TCHARszDataSourceName[MAX_STRING_SIZE] = TEXT(""); 
TCHARrgbValue[SQL_MAX_MESSAGE_LENGTH]; 
TCHARszAPI[MEDBUFF]=TEXT(""); 
TCHARszBuff[MEDBUFF]=TEXT(""); 
RETCODErcExp=SQL_SUCCESS; 
 
HANDLES rgHandles[] =  
{ 
SQL_HANDLE_ENV, henv, 
SQL_HANDLE_DBC, hdbc, 
SQL_HANDLE_STMT, hstmt, 
SQL_HANDLE_DESC, hdesc, 
}; 
 
cHandles=sizeof(rgHandles)/sizeof(HANDLES); 
 
/* Call SQLGetInfo to get values to compare: */ 
rcFunction = SQLGetInfo(hdbc, SQL_DATA_SOURCE_NAME, szDataSourceName, MAX_STRING_SIZE, NULL); 
RETCHECK(SQL_SUCCESS, rcFunction, szSQLGETINFO); 
 
hdesc = SQL_NULL_HDESC; 
 
/* Allocate an hdesc: */ 
if(Supported(SQL_API_SQLALLOCHANDLE) && g_f3XDriver) 
{  
rcFunction = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc); 
RETCHECK(SQL_SUCCESS, rcFunction, szSQLALLOCHANDLE); 
 
// Update the array entry for the hdesc 
rgHandles[3].hHandle=hdesc; 
 
} 
else 
cHandles--; 
 
for (iHandle=0; iHandle < cHandles; iHandle++) 
{ 
 
SetErrorCondition(rgHandles[iHandle].fHandleType); 
 
if(fDiagFieldSupported) 
{ 
for (iField=0;iField < sizeof(rgDiagInfo)/sizeof(struct tagDIAGINFO);iField++) 
{ 
rc = SQLGetDiagField(rgHandles[iHandle].fHandleType, rgHandles[iHandle].hHandle,  
rgDiagInfo[iField].irecRecNumber, rgDiagInfo[iField].uwDescField, 
rgbValue, SQL_MAX_MESSAGE_LENGTH, &cbValue); 
 
DIAGRETCHECK(rcExp, rc, szSQLGETDIAGFIELD); 
 
if (RC_SUCCESSFUL(rc)) 
CheckData(rgHandles[iHandle].fHandleType,rgDiagInfo[iField].uwDescField,  
rgbValue,szDataSourceName); 
} 
 
} 
else 
{ 
rc = SQLGetDiagField(SQL_HANDLE_ENV, henv, 0, SQL_DIAG_RETURNCODE, rgbValue,SQL_MAX_MESSAGE_LENGTH, &cbValue); 
 
if(!FindError(rgHandles[iHandle].fHandleType, szIM001)) 
DISPLAYERROR(szAPI, szNotSupported); 
 
} 
 
} 
 
 
/* Free the hdesc: */ 
if (hdesc) 
{ 
rcFunction = SQLFreeHandle(SQL_HANDLE_DESC, hdesc); 
RETCHECK(rcExp, rcFunction, szSQLFREEHANDLE); 
hdesc = SQL_NULL_HDESC; 
} 
 
//ExitTestDiagField 
 
FreeStmt(SQL_CLOSE); 
 
} /* TestDiagField() */ 
 
//------------------------------------------------------------------------------ 
//Function:CompareAnsiToUnicode 
//Compares an ANSI string to a Unicode string 
//------------------------------------------------------------------------------ 
BOOL CompareAnsiToUnicode(SQLCHAR * aszBuf, SQLINTEGER cbA, SQLWCHAR * wszBuf, 
SQLINTEGER cbW, SQLTCHAR * szAPI) 
{ 
SQLCHAR aszConvBuf[MAX_STRING_SIZE]; 
SQLINTEGER cbT; 
BOOL bCompare=TRUE; 
 
// Check ANSI count of bytes returned 
if ((cbA != SQL_NULL_DATA) && (SQLINTEGER)strlen(aszBuf) != cbA) 
{ 
wsprintf(buf, TEXT("ANSI count of bytes returned incorrect.")\ 
TEXT(" Expected: %d, received: %d"), 
strlen(aszBuf), cbA); 
DISPLAYERROR(szAPI, buf); 
bCompare=FALSE; 
} 
 
// Compare ANSI count of bytes with Unicode count 
cbT = (cbA > 0) ? (SQLINTEGER)(cbA * sizeof(SQLWCHAR)) : cbA; 
if (cbW != cbT) 
{ 
wsprintf(buf, TEXT("Unicode count of bytes returned incorrect.")\ 
TEXT(" Expected: %d, received: %d"), cbT, cbW); 
DISPLAYERROR(szAPI, buf); 
bCompare=FALSE; 
} 
 
// Compare strings if not NULL DATA 
if (cbA != SQL_NULL_DATA) 
{ 
// Compare ANSI and Unicode strings returned 
(void)(WideCharToMultiByte(CP_ACP, 0, wszBuf, wcslen(wszBuf), aszConvBuf, 
sizeof(aszConvBuf), NULL, NULL)); 
aszConvBuf[wcslen(wszBuf)]=TEXT('\0'); 
 
if (strcmp(aszBuf, aszConvBuf)) 
{ 
wsprintf(buf, TEXT("Unicode string did not match ANSI string.\r\n")\ 
TEXT("\t\t\tExpected: '%hs', Received: '%hs'"), aszBuf, aszConvBuf); 
DISPLAYERROR(szAPI, buf); 
bCompare=FALSE; 
} 
} 
 
return bCompare; 
} 
 
//------------------------------------------------------------------------------ 
//Function:CompareAnsiUnicodeResults 
//Compares an ANSI result set to a Unicode result set 
//------------------------------------------------------------------------------ 
void CompareAnsiUnicodeResults(SQLHSTMT hstmtA, SQLHSTMT hstmtW, SQLTCHAR * szAPI) 
{ 
SQLCHAR aszBuf[MAX_STRING_SIZE]; 
SQLWCHAR wszBuf[MAX_STRING_SIZE]; 
SQLINTEGER cbANSI, cbUnicode; 
SQLUSMALLINTuwCol; 
SQLSMALLINTswColCountA, swColCountW; 
SQLRETURN rc, rcA, rcW; 
 
// Check width of result sets 
rc=SQLNumResultCols(hstmtA, &swColCountA); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtA, SQL_SUCCESS, rc, szSQLNUMRESULTCOLS); 
rc=SQLNumResultCols(hstmtW, &swColCountW); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_SUCCESS, rc, szSQLNUMRESULTCOLS); 
if (swColCountA != swColCountW) 
DISPLAYERROR(szAPI,TEXT("ANSI and Unicode result sets different widths.")); 
 
uwCol=1; 
do { 
rc=SQLBindCol(hstmtA, uwCol, SQL_C_CHAR, aszBuf, sizeof(aszBuf), &cbANSI); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtA, SQL_SUCCESS, rc, szSQLBINDCOL); 
rc=SQLBindCol(hstmtW, uwCol, SQL_C_WCHAR, wszBuf, sizeof(wszBuf), &cbUnicode); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_SUCCESS, rc, szSQLBINDCOL); 
 
// Copy something into the buffers so we can tell if they were modified 
strcpy(aszBuf, "Untouched"); 
wcscpy(wszBuf, L"Untouched"); 
 
// Fetch into the buffers 
rcA=SQLFetch(hstmtA); 
rcW=SQLFetch(hstmtW); 
 
 
if (RC_SUCCESSFUL(rcA) && RC_SUCCESSFUL(rcW)) 
{ 
if (!CompareAnsiToUnicode(aszBuf, cbANSI, wszBuf, cbUnicode, szSQLFETCH)) 
{ 
rcW=SQL_NO_DATA;// Abort the loop w/o generating failure 
rcA=SQL_NO_DATA; 
} 
} 
 
// Unbind the column bound above on each statement 
rc=SQLFreeStmt(hstmtA, SQL_UNBIND); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtA, SQL_SUCCESS, rc, szSQLFREESTMT); 
rc=SQLFreeStmt(hstmtW, SQL_UNBIND); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_SUCCESS, rc, szSQLFREESTMT); 
 
// Don't exceed the total number of columns in result set 
uwCol++; 
if (uwCol > (SQLUSMALLINT)swColCountA) 
uwCol=1; 
} 
while (RC_SUCCESSFUL(rcA) && RC_SUCCESSFUL(rcW)); 
 
// Make sure the result sets were the same size 
if (rcW != SQL_NO_DATA) 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_NO_DATA, rc, szSQLFETCH); 
 
// Make sure the result sets were the same size 
if (rcA != rcW) 
DISPLAYERROR(szAPI,TEXT("ANSI and Unicode result sets not the same length.")); 
 
rc=SQLFreeStmt(hstmtA, SQL_CLOSE); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtA, SQL_SUCCESS, rc, szSQLFREESTMT); 
rc=SQLFreeStmt(hstmtW, SQL_CLOSE); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_SUCCESS, rc, szSQLFREESTMT); 
 
} 
 
 
/*------------------------------------------------------------------------------ 
/Function:TestMixedAnsiUnicode 
/Purpose:Call several of the Unicode functions mixed with ANSI functions 
/to verify functions succeed in the mixed case. 
/*----------------------------------------------------------------------------*/ 
void PASCAL TestMixedAnsiUnicode(QTSTRUCT * lpqt) 
{ 
HDBChdbcANSI, hdbcUnicode; 
HSTMT hstmtANSIA, hstmtANSIW, hstmtUA, hstmtUW, hstmtW; 
SQLINTEGER cbANSI, cbUnicode; 
SQLWCHAR wszServer[MAX_STRING_SIZE], wszLogin[MAX_STRING_SIZE], 
wszPassword[MAX_STRING_SIZE], wszQuery[MAX_STRING_SIZE], 
wszBuf[MAX_STRING_SIZE], wszTable[MAX_STRING_SIZE]; 
SQLCHARaszServer[MAX_STRING_SIZE], aszLogin[MAX_STRING_SIZE], 
aszPassword[MAX_STRING_SIZE], aszQuery[MAX_STRING_SIZE], 
aszBuf[MAX_STRING_SIZE], aszTable[MAX_STRING_SIZE]; 
SQLUSMALLINT fStmts; 
SQLRETURN rc, rcA=SQL_SUCCESS, rcW=SQL_SUCCESS; 
 
// We've already set the environment attribute to 3.0 by this point 
 
#ifdef UNICODE 
// Copy the unicode strings 
lstrcpy(wszServer, lpSI->szValidServer0); 
lstrcpy(wszLogin, lpSI->szValidLogin0); 
lstrcpy(wszPassword, lpSI->szValidPassword0); 
lstrcpy(wszTable, lpqt->szTableName); 
wsprintf(wszQuery,szSELECTSTAR,lpqt->szTableName); 
 
// Convert and copy to ANSI strings 
/* 
int WideCharToMultiByte( 
 UINT  CodePage,// code page  
 DWORD  dwFlags,// performance and mapping flags  
 LPCWSTR  lpWideCharStr,// address of wide-character string  
 int  cchWideChar,// number of characters in string  
 LPSTR  lpMultiByteStr,// address of buffer for new string  
 int  cchMultiByte,// size of buffer  
 LPCSTR  lpDefaultChar,// address of default for unmappable characters   
 LPBOOL  lpUsedDefaultChar // address of flag set when default char. used  
); 
*/ 
// Server 
(void)(WideCharToMultiByte(CP_ACP, 
  0, 
  lpSI->szValidServer0, 
  lstrlen(lpSI->szValidServer0), 
  aszServer, 
  sizeof(aszServer), 
  NULL, 
  NULL)); 
aszServer[lstrlen(lpSI->szValidServer0)]=TEXT('\0'); 
 
// UID 
(void)(WideCharToMultiByte(CP_ACP, 
  0, 
  lpSI->szValidLogin0, 
  lstrlen(lpSI->szValidLogin0), 
  aszLogin, 
  sizeof(aszLogin), 
  NULL, 
  NULL)); 
aszLogin[lstrlen(lpSI->szValidLogin0)]=TEXT('\0'); 
 
// PWD 
(void)(WideCharToMultiByte(CP_ACP, 
  0, 
  lpSI->szValidPassword0, 
  lstrlen(lpSI->szValidPassword0), 
  aszPassword, 
  sizeof(aszPassword), 
  NULL, 
  NULL)); 
aszPassword[lstrlen(lpSI->szValidPassword0)]=TEXT('\0'); 
 
// Select stmt 
(void)(WideCharToMultiByte(CP_ACP, 
  0, 
  wszQuery, 
  lstrlen(wszQuery), 
  aszQuery, 
  sizeof(aszQuery), 
  NULL, 
  NULL)); 
aszQuery[lstrlen(wszQuery)]=TEXT('\0'); 
 
// Table name 
(void)(WideCharToMultiByte(CP_ACP, 
  0, 
  wszTable, 
  lstrlen(wszTable), 
  aszQuery, 
  sizeof(aszTable), 
  NULL, 
  NULL)); 
aszTable[lstrlen(wszTable)]=TEXT('\0'); 
 
#else 
// Copy the ANSI strings 
lstrcpy(aszServer, lpSI->szValidServer0); 
lstrcpy(aszLogin, lpSI->szValidLogin0); 
lstrcpy(aszPassword, lpSI->szValidPassword0); 
lstrcpy(aszTable, lpqt->szTableName); 
wsprintf(aszQuery,szSELECTSTAR,lpqt->szTableName); 
 
// Convert and copy to Unicode strings 
/* 
int MultiByteToWideChar( 
 UINT  CodePage,// code page  
 DWORD  dwFlags,// character-type options  
 LPCSTR  lpMultiByteStr,// address of string to map  
 int  cchMultiByte,// number of characters in string  
 LPWSTR  lpWideCharStr,// address of wide-character buffer  
 int  cchWideChar // size of buffer  
); 
*/ 
 
// Server 
(void) MultiByteToWideChar(CP_ACP, 
0, 
lpSI->szValidServer0, 
lstrlen(lpSI->szValidServer0), 
wszServer, 
sizeof(wszServer)/sizeof(WCHAR) 
); 
wszServer[lstrlen(lpSI->szValidServer0)]=TEXT('\0'); 
 
// UID 
(void) MultiByteToWideChar(CP_ACP, 
0, 
lpSI->szValidLogin0, 
lstrlen(lpSI->szValidLogin0), 
wszLogin, 
sizeof(wszLogin)/sizeof(WCHAR) 
); 
wszLogin[lstrlen(lpSI->szValidLogin0)]=TEXT('\0'); 
 
// PWD 
(void) MultiByteToWideChar(CP_ACP, 
0, 
lpSI->szValidPassword0, 
lstrlen(lpSI->szValidPassword0), 
wszPassword, 
sizeof(wszPassword)/sizeof(WCHAR) 
); 
wszPassword[lstrlen(lpSI->szValidPassword0)]=TEXT('\0'); 
 
// Select stmt 
(void) MultiByteToWideChar(CP_ACP, 
0, 
aszQuery, 
lstrlen(aszQuery), 
wszQuery, 
sizeof(wszQuery)/sizeof(WCHAR) 
); 
wszQuery[lstrlen(aszQuery)]=TEXT('\0'); 
 
// Table name 
(void) MultiByteToWideChar(CP_ACP, 
0, 
aszTable, 
lstrlen(aszTable), 
wszTable, 
sizeof(wszTable)/sizeof(WCHAR) 
); 
wszTable[lstrlen(aszTable)]=TEXT('\0'); 
 
#endif 
 
// Allocate connection for ANSI 
rc = SQLAllocConnect(henv, &hdbcANSI); 
RETCHECK(SQL_SUCCESS, rc, szSQLALLOCCONNECT); 
 
// Allocate connection for Unicode 
rc = SQLAllocConnect(henv, &hdbcUnicode); 
RETCHECK(SQL_SUCCESS, rc, szSQLALLOCCONNECT); 
 
// If Unicode is defined, then strings need to be converted to ANSI 
// before calling SQLConnectA 
rc = SQLConnectA(hdbcANSI, (LPSTR)aszServer, SQL_NTS, 
(LPSTR)aszLogin, SQL_NTS, 
(LPSTR)aszPassword, SQL_NTS); 
if (!RC_SUCCESSFUL(rc)) 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLCONNECT); 
 
rc = SQLConnectW(hdbcUnicode, (LPWSTR)wszServer, SQL_NTS, 
(LPWSTR)wszLogin, SQL_NTS, 
(LPWSTR)wszPassword, SQL_NTS); 
if (!RC_SUCCESSFUL(rc)) 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcUnicode, SQL_SUCCESS, rc,szSQLCONNECTW); 
 
// Test mixed SQLNativeSQL callson the ANSI connection 
rc=SQLNativeSqlA(hdbcANSI, aszQuery, strlen(aszQuery), aszBuf, sizeof(aszBuf), &cbANSI); 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLNATIVESQL); 
rc=SQLNativeSqlW(hdbcANSI,wszQuery, wcslen(wszQuery)*sizeof(WCHAR), wszBuf, sizeof(wszBuf), 
&cbUnicode); 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLNATIVESQL); 
 
CompareAnsiToUnicode(aszBuf, cbANSI, wszBuf, cbUnicode, szSQLNATIVESQLW); 
 
// Allocate stmt handles for ANSI connection 
rc = SQLAllocStmt(hdbcANSI, &hstmtANSIA);// Handle for ANSI calls 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLALLOCSTMT); 
rc = SQLAllocStmt(hdbcANSI, &hstmtANSIW);// Handle for Unicode calls 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLALLOCSTMT); 
 
// Allocate stmt handles for Unicode connection 
rc = SQLAllocStmt(hdbcUnicode, &hstmtUA); // Handle for ANSI calls 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcUnicode, SQL_SUCCESS, rc,szSQLALLOCSTMT); 
rc = SQLAllocStmt(hdbcUnicode, &hstmtUW); // Handle for Unicode calls 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcUnicode, SQL_SUCCESS, rc,szSQLALLOCSTMT); 
 
// Call SQLTablesA&W on two different hdbcs 
strcpy(aszBuf,"%"); 
wcscpy(wszBuf,L"%"); 
rc = SQLTablesA(hstmtANSIA, NULL, 0, NULL, 0, aszBuf, SQL_NTS, NULL, 0); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtANSIA, SQL_SUCCESS, rc, szSQLTABLESA); 
rc = SQLTablesW(hstmtUW, NULL, 0, NULL, 0, wszBuf, SQL_NTS, NULL, 0); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtUW, SQL_SUCCESS, rc, szSQLTABLESW); 
 
// Compare the two result sets 
CompareAnsiUnicodeResults(hstmtANSIA, hstmtUW, szSQLTABLESW); 
 
// See if the driver supports multiple active stmts 
rc = SQLGetInfo(hdbcANSI, SQL_ACTIVE_STATEMENTS, &fStmts, 0, NULL); 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc, szSQLGETINFO); 
 
// Create a search string for ANSI 
aszBuf[0]=aszTable[0]; 
aszBuf[1]=TEXT('\0'); 
strcat(aszBuf,"%"); 
 
// Create a search string for Unicode 
wszBuf[0]=wszTable[0]; 
wszBuf[1]=TEXT('\0'); 
wcscat(wszBuf,L"%"); 
 
// If the allowed active statements is > 1, then use the same connection 
// otherwise use the other connection 
if (fStmts > 1) 
hstmtW=hstmtUW; 
else 
hstmtW=hstmtANSIW; 
 
// Call SQLColumnsA&W on two different hstmts (same connection if allowed) 
// Call for only the given table to limit compare errors at this time 
rc = SQLColumnsA(hstmtUA, NULL, 0, NULL, 0, aszTable, SQL_NTS, NULL, 0); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtANSIA, SQL_SUCCESS, rc, szSQLCOLUMNSA); 
 
// Call for only the given table to limit compare errors at this time 
rc = SQLColumnsW(hstmtW, NULL, 0, NULL, 0, wszTable, SQL_NTS, NULL, 0); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_SUCCESS, rc, szSQLCOLUMNSW); 
 
CompareAnsiUnicodeResults(hstmtUA, hstmtW, szSQLCOLUMNSW); 
 
rc = SQLExecDirectA(hstmtUA, aszQuery, SQL_NTS); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtUA, SQL_SUCCESS, rc, szSQLEXECDIRECTA); 
 
// Call for only the given table to limit compare errors at this time 
rc = SQLExecDirectW(hstmtW, wszQuery, SQL_NTS); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_SUCCESS, rc, szSQLEXECDIRECTW); 
 
CompareAnsiUnicodeResults(hstmtUA, hstmtW, szSQLEXECDIRECTW); 
 
// Disconnect and free ANSI handles 
rc=SQLFreeStmt(hstmtANSIA, SQL_DROP); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtANSIA, SQL_SUCCESS, rc,szSQLFREESTMT); 
rc=SQLFreeStmt(hstmtANSIW, SQL_DROP); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtANSIW, SQL_SUCCESS, rc,szSQLFREESTMT); 
rc=SQLDisconnect(hdbcANSI); 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLCONNECT); 
rc=SQLFreeConnect(hdbcANSI); 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLCONNECT); 
// Disconnect and free Unicode handles 
rc=SQLFreeStmt(hstmtUA, SQL_DROP); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtUA, SQL_SUCCESS, rc,szSQLFREESTMT); 
rc=SQLFreeStmt(hstmtUW, SQL_DROP); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmtUW, SQL_SUCCESS, rc,szSQLFREESTMT); 
rc=SQLDisconnect(hdbcUnicode); 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcUnicode, SQL_SUCCESS, rc,szSQLCONNECT); 
rc=SQLFreeConnect(hdbcUnicode); 
ERRSHANDLE(SQL_HANDLE_DBC, hdbcUnicode, SQL_SUCCESS, rc,szSQLCONNECT); 
 
} /* TestMixedAnsiUnicode() */ 
 
//----------------------------------------------------------------------- 
//      Function:               TestStmtOptions 
//----------------------------------------------------------------------- 
 
void  PASCAL TestStmtOptions() 
{ 
UDWORDdwLen, 
udw; 
BOOLfConnectOption; 
RETCODErc=SQL_SUCCESS; 
TCHARszAPI[MEDBUFF]; 
SDWORDcbValue=0; 
 
SetStatementAttributes(SQL_MAX_LENGTH,(PTR)&udw); 
 
if (SetStatementAttributes(SQL_MAX_LENGTH, (PTR)TEST_STMT_OPTION)) 
fConnectOption = TRUE; 
 
if (Supported(SQL_API_SQLGETSTMTATTR)) 
{ 
rc = SQLGetStmtAttr(hstmt, SQL_MAX_LENGTH, (PTR)&dwLen,sizeof(dwLen),&cbValue); 
lstrcpy(szAPI,szSQLGETSTMTATTR); 
} 
else 
{ 
rc = SQLGetStmtOption(hstmt, SQL_MAX_LENGTH, &dwLen); 
lstrcpy(szAPI,szSQLGETSTMTOPTION); 
} 
 
if(rc != SQL_SUCCESS) 
{ 
if(!FindError(SQL_HANDLE_STMT,szHYC00)) 
RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTOPTION); 
} 
else 
{ 
if(dwLen != TEST_STMT_OPTION && rc == SQL_SUCCESS && fConnectOption) 
DISPLAYERROR(szSQLGETSTMTOPTION,TEXT("incorrect SQL_MAX_LENGTH value returned")); 
} 
 
 
} //TestStmtOptions() 
 
 
//----------------------------------------------------------------------- 
//      Function:               SetTableName 
//----------------------------------------------------------------------- 
 
void  PASCAL SetTableName(QTSTRUCT  *lpqt) 
{ 
RETCODErc=SQL_SUCCESS; 
UWORDcTableName; 
TCHARszTime[MEDBUFF]=TEXT(""), 
szTmpBuff[MEDBUFF], 
*pTime=NULL; 
 
_tstrtime(szTmpBuff); 
 
/* Remove colons */ 
pTime=_tcstok(szTmpBuff, TEXT(":")); 
while (pTime) 
{ 
lstrcat(szTime,pTime); 
pTime=_tcstok(NULL, TEXT(":")); 
} 
  
rc = SQLGetInfo(hdbc, SQL_MAX_TABLE_NAME_LEN, &cTableName, 
sizeof (int), NULL); 
if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) 
RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); 
 
rc = SQLGetInfo(hdbc, SQL_QUALIFIER_NAME_SEPARATOR, lpqt->buf, 
MAX_STRING_SIZE, NULL); 
if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) 
RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); 
 
if(!lstrcmp(TEXT("\\"), lpqt->buf)) 
cTableName -= 4; 
 
_sntprintf(lpqt->szTableName, min(cTableName, MAX_TABLE_NAME-1), 
TEXT("q%s"), szTime); 
 
} //SetTableName() 
 
 
//----------------------------------------------------------------------- 
//      Function:               AllowedType 
// 
//If swNumTypes > 0, limits SQL types to those in array 
//----------------------------------------------------------------------- 
BOOL AllowedType(SWORD fType) 
{ 
SWORD i, swNumTypes=0; 
BOOL bAllowed=TRUE; 
SWORD rgAllowedTypes[MAX_TYPES_SUPPORTED]={ 
SQL_CHAR, 
SQL_BINARY 
//SQL_BIT 
/* 
SQL_TINYINT 
SQL_NUMERIC, 
SQL_INTEGER, 
SQL_SMALLINT, 
SQL_FLOAT, 
SQL_REAL, 
SQL_TYPE_TIMESTAMP, 
SQL_LONGVARBINARY, 
SQL_LONGVARCHAR 
*/ 
}; 
 
if (swNumTypes > 0) 
{ 
bAllowed=FALSE; 
 
for (i=0; i < swNumTypes; i++) 
{ 
if (fType == rgAllowedTypes[i]) 
bAllowed=TRUE; 
} 
} 
 
return bAllowed; 
} 
 
//----------------------------------------------------------------------- 
//      Function:               GetTypeInfo 
//----------------------------------------------------------------------- 
 
UWORD  PASCAL GetTypeInfo(FIELDINFO  *rgFields,QTSTRUCT  *lpqt) 
{ 
RETCODErc=SQL_SUCCESS; 
UWORD       cFieldName; 
SDWORD      cMaxTypeSize, cMaxRowSize; 
UWORD       i, 
cTypes=0; 
SDWORD      sdw; 
LPTSTR       pch=NULL; 
BOOLfAutoInc=0; 
 
/* Get the type information to use in a create statement for a table */ 
 
rc = SQLGetInfo(hdbc, SQL_MAX_COLUMN_NAME_LEN, &cFieldName, 
sizeof cFieldName, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); 
 
rc = SQLGetInfo(hdbc, SQL_MAX_ROW_SIZE, &cMaxRowSize, 
sizeof cMaxRowSize, NULL); 
/* don't check for SQL_SUCCES here, it's a 2.0 function.  If it's successful 
That's great, if not then no maximum is assumed. */ 
 
cMaxTypeSize = cMaxRowSize / MAX_TYPES_SUPPORTED; 
 
/* TO DO: add checks in here for dos file types GetInfo SQL_QUALIFIER_NAME_SEPARATER */ 
 
if(cFieldName > MAX_FIELD - 1) 
cFieldName = MAX_FIELD - 1; 
 
if(cFieldName < PREFIX_SIZE) 
{ 
DISPLAYERROR(szSQLGETINFO,TEXT("MAX_COLUMN_NAME_LEN is too small for autotest to run")); 
goto TypeErrorRet; 
} 
 
rc = SQLGetTypeInfo(hstmt, SQL_ALL_TYPES); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETTYPEINFO); 
 
for(i = 0; i < MAX_TYPES_SUPPORTED; i++) 
{ 
 
rc = SQLFetch(hstmt); 
if(rc != SQL_SUCCESS && rc !=SQL_SUCCESS_WITH_INFO) 
break; 
 
*rgFields[i].szType = *rgFields[i].szLength = *rgFields[i].szParams = TEXT('\0'); 
 
/* get type name */ 
rc = SQLGetData(hstmt, 1, SQL_C_TCHAR, 
rgFields[i].szType, MAX_TYPE_NAME, &sdw); 
 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA)) 
goto TypeErrorRet; 
 
wsprintf(rgFields[i].szFieldName,TEXT("c%02u"), i+COLNAME_START); 
/* copy first portion of type name for easy reference */ 
_tcsnccat(rgFields[i].szFieldName, rgFields[i].szType, TYPE_PORTION); 
 
 
/* change spaces in field name to '_' */ 
while((pch = (LPTSTR)_tcschr(rgFields[i].szFieldName, TEXT(' '))) != NULL) 
*pch = TEXT('_'); 
 
/* get the SQLType */ 
rc = SQLGetData(hstmt, 2, SQL_C_DEFAULT, 
(SWORD  *)&rgFields[i].wSQLType, IGNORED, 
&sdw); 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA)) 
goto TypeErrorRet; 
 
/* Max length */ 
rc = SQLGetData(hstmt, 3, SQL_C_TCHAR, 
rgFields[i].szLength, MAX_FIELD, &sdw); 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA)) 
goto TypeErrorRet; 
 
/* limit the row size for those drivers that don't support a long 
enough row length for all the fields to be at the max length */ 
switch(rgFields[i].wSQLType) 
{ 
case SQL_CHAR: 
case SQL_VARCHAR: 
case SQL_VARBINARY: 
case SQL_BINARY: 
case SQL_LONGVARCHAR: 
case SQL_LONGVARBINARY: 
 
if(cMaxTypeSize) 
{ 
if(_ttol (rgFields[i].szLength) > cMaxTypeSize) 
_ltot(cMaxTypeSize, rgFields[i].szLength, 10); 
} 
} 
 
/* prefix */ 
rc = SQLGetData(hstmt, 4, SQL_C_TCHAR, 
rgFields[i].szPrefix, MAX_PREFIX, &sdw); 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA)) 
goto TypeErrorRet; 
 
/* suffix */ 
rc = SQLGetData(hstmt, 5, SQL_C_TCHAR, 
rgFields[i].szSuffix, MAX_SUFFIX, &sdw); 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA)) 
goto TypeErrorRet; 
 
/* create params */ 
rc = SQLGetData(hstmt, 6, SQL_C_TCHAR, 
rgFields[i].szParams, MAX_PARAM_SIZE, &sdw); 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA)) 
goto TypeErrorRet; 
 
/* nullable */ 
rc = SQLGetData(hstmt, 7, SQL_C_SHORT, &rgFields[i].nullable, IGNORED, 
&sdw); 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA)) 
goto TypeErrorRet; 
 
/* searchable */ 
rc = SQLGetData(hstmt, 9, SQL_C_SHORT, &rgFields[i].fSearchable, IGNORED, 
&sdw); 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA)) 
goto TypeErrorRet; 
 
/* autoincrement */ 
rc = SQLGetData(hstmt, 12, SQL_C_SHORT, &rgFields[i].autoinc, IGNORED, 
&sdw); 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA)) 
goto TypeErrorRet; 
 
// Since some data types will have NULL for autoincrement, we need to set to FALSE 
if (SQL_NULL_DATA == sdw) 
rgFields[i].autoinc=FALSE; 
 
if (IgnoreType(rgFields[i].szType,rgFields[i].wSQLType)) 
{ 
i--; 
continue; 
} 
 
/* The following code only allows the first autoincrement column to 
be placed in the table.  Many DBMS's do not allow more than one per table. */ 
if(rgFields[i].autoinc == TRUE) 
{ 
if(fAutoInc) 
{ 
i--; 
continue; 
} 
else 
fAutoInc = TRUE; 
} 
 
// Limit data types to those desired (use for debugging) 
if (!AllowedType(rgFields[i].wSQLType)) 
{ 
i--; 
continue; 
} 
} 
 
cTypes = i; 
 
/* if the type name contains spaces, replace them with _ because 
most servers don't allow spaces in field names */ 
 
RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH); 
 
rc = SQLFreeStmt(hstmt, SQL_CLOSE); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT); 
 
SetTableName(lpqt); 
 
return(cTypes); 
 
TypeErrorRet: 
 
return(0); 
 
} //GetTypeInfo() 
 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               BuildCreateStmt 
//----------------------------------------------------------------------- 
 
BOOL  PASCAL BuildCreateStmt(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes) 
{ 
RETCODErc=SQL_SUCCESS; 
TCHAR        szNum[MAX_NUM_BUFFER];   /* used with _ttoi and itoa conversions */ 
SWORD       wNum; 
UWORD       i; 
SDWORD      sdw; 
LPTSTR       pch=NULL; 
 
 
/* the column names will be ctypname (where typename is the 
type name returned by the source in SQLGetTypeInfo) */ 
 
*lpqt->sz = TEXT('\0'); 
lstrcpy(lpqt->sz,TEXT("Create Table ")); 
lstrcat(lpqt->sz, lpqt->szTableName); 
lstrcat(lpqt->sz,TEXT(" (")); 
for(i = 0; i < cTypes; i++) { 
TCHAR szParamType[50]; 
TCHAR szNotNull[10]; 
*lpqt->szParam = TEXT('\0'); 
 
/* if SQLGetTypeInfo returned params they need to be used in 
the create statement */ 
 
if(rgFields[i].szParams == NULL || lstrlen(rgFields[i].szParams) == 0) 
*lpqt->szParam = TEXT('\0'); 
else if(_tcschr(rgFields[i].szParams, TEXT(',')) == NULL) 
wsprintf(lpqt->szParam,TEXT("(%s)"), rgFields[i].szLength); 
else 
{ 
lstrcpy(szNum, rgFields[i].szLength); 
wsprintf(lpqt->szParam,TEXT("(%s, %d)"), rgFields[i].szLength, 
_ttoi(szNum) - SCALEDIFF); 
} 
 
lstrcpy(szParamType, rgFields[i].szType); 
if(pch = _tcschr((LPTSTR)szParamType, TEXT('(')))  
{ 
*pch = TEXT('\0'); 
lstrcat(szParamType, lpqt->szParam); 
lstrcat(szParamType, (LPTSTR)_tcschr(rgFields[i].szType, TEXT(')')) + 1); 
} 
else 
{ 
lstrcat(szParamType, lpqt->szParam); 
} 
 
/* If the field is not nullable, we need to create the table that way */ 
rc = SQLGetInfo(hdbc, SQL_NON_NULLABLE_COLUMNS, &wNum, 
sizeof (SWORD), NULL); 
if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) 
RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); 
 
if((rgFields[i].nullable == SQL_NO_NULLS) && (wNum != SQL_NNC_NULL)) 
lstrcpy(szNotNull,TEXT("NOT NULL")); 
else 
szNotNull[0] = TEXT('\0'); 
 
wsprintf(&lpqt->sz[lstrlen(lpqt->sz)],TEXT(" %s %s %s ,"), 
rgFields[i].szFieldName, (LPTSTR)szParamType, (LPTSTR)szNotNull); 
} 
 
/* remove the last comma and space */ 
lpqt->sz[lstrlen(lpqt->sz) - 2] = TEXT('\0'); 
lstrcat(lpqt->sz,TEXT(")")); 
 
rc = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS); 
if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT)) 
goto BuildErrorRet; 
 
/* now that table was created, call SQLColumns.  Both as 
a test and to get necessary information to insert data */ 
 
rc = SQLColumns(hstmt, NULL, SQL_NTS, NULL, SQL_NTS, 
lpqt->szTableName, SQL_NTS, NULL, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLCOLUMNS); 
 
for(i = 0; i < cTypes; i++) { 
rc = SQLFetch(hstmt); 
RETCHECK(SQL_SUCCESS, rc,szSQLFETCH); 
 
/* precision */ 
rc = SQLGetData(hstmt, 7, SQL_C_LONG, &rgFields[i].precision, IGNORED, 
&sdw); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); 
 
/* length */ 
if((rgFields[i].precision == 0) || (sdw == SQL_NO_TOTAL)){ 
rc = SQLGetData(hstmt, 8, SQL_C_LONG, &rgFields[i].precision, IGNORED, 
&sdw); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); 
if(sdw == SQL_NO_TOTAL)/* precision & length were undetermined */ 
rgFields[i].precision = 1000;/* so set it to an arbitary value */ 
} 
 
/* numeric scale */ 
rc = SQLGetData(hstmt, 9, SQL_C_SHORT, &rgFields[i].scale, IGNORED, 
&sdw); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); 
if(sdw == SQL_NO_TOTAL) 
rgFields[i].scale = 0; 
} 
 
rc = SQLFreeStmt(hstmt, SQL_CLOSE); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT); 
 
/* look for columns the test should not try to update by running 
a select * query and calling ColAttributes on the result fields */ 
/* select * does not return the fields in a defined order, so field order 
must be specified */ 
 
lstrcpy(lpqt->sz,TEXT("select ")); 
for(i = 0; i < cTypes; i ++) { 
if(i) 
lstrcat(lpqt->sz,TEXT(",")); 
lstrcat(lpqt->sz, rgFields[i].szFieldName); 
} 
 
lstrcat(lpqt->sz,TEXT(" from ")); 
lstrcat(lpqt->sz, lpqt->szTableName); 
 
rc = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
for(i = 1; i <= cTypes; i++) { 
 
rc = SQLColAttributes(hstmt, i, SQL_COLUMN_UPDATABLE, NULL, 
0, NULL, &sdw); 
RETCHECK(SQL_SUCCESS, rc,szSQLCOLATTRIBUTES); 
 
rgFields[i - 1].fAutoUpdate = sdw == SQL_ATTR_READONLY; 
 
rc = SQLColAttributes(hstmt, i, SQL_COLUMN_UNSIGNED, NULL, 
0, NULL, &sdw); 
RETCHECK(SQL_SUCCESS, rc,szSQLCOLATTRIBUTES); 
 
rgFields[i - 1].fUnsigned = sdw; 
} 
 
rc = SQLFreeStmt(hstmt, SQL_CLOSE); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT); 
 
return(FALSE); 
 
BuildErrorRet: 
 
return(TRUE); 
 
} //BuildCreateStmt() 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               BuildInsertStmt 
//----------------------------------------------------------------------- 
   
BOOL  PASCAL BuildInsertStmt(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes, 
DSTRUCT  *lpd,SDWORD  *cColsSelected,BOOL fBindParameter) 
{ 
RETCODE  rc; 
UWORD    w; 
UWORD    i; 
PTRptr; 
UWORD    ind; 
SDWORD   sdw; 
LPTSTR    pch=NULL; 
BOOLfColNames=TRUE, 
fLongData=FALSE; 
SDWORD  *sdwArray = (SDWORD  *)AllocateMemory(sizeof(SDWORD) * MAX_TYPES_SUPPORTED); 
 
lstrcpy(lpqt->szColNames,TEXT("\0")); 
lstrcpy(lpqt->szValues,TEXT("\0")); 
 
for(i = 0; i < cTypes; i++) { 
 
for(ind = 0, w = 0; ind < cTypes; ind++) { 
 
pch = qtMakeData(i, ind,&rgFields[ind], lpqt->szDataItem); 
 
if(!pch) /* current type is READ_ONLY) */ 
continue; 
 
/* for every nullable type, that field will be set to */ 
/* null when the row number corresponds with the field */ 
/* number */ 
 
if(*pch)  
{ 
lstrcpy(lpd[w].data, pch); 
lpd[w].cb = SQL_NTS; 
} 
else  
{ 
lstrcpy(lpd[w].data,TEXT("")); 
lpd[w].cb = SQL_NULL_DATA; 
} 
 
if(fColNames)  
{ 
/* the first time throught, the insert */ 
/* statement itself is created         */ 
lstrcat(lpqt->szColNames, rgFields[ind].szFieldName); 
lstrcat(lpqt->szColNames,TEXT(", ")); 
lstrcat(lpqt->szValues,TEXT(" ?, ")); 
 
/* and parameters are set */ 
/* set all the parameters using pointers to buffers in*/ 
/* the param struct. */ 
if(!fBindParameter) 
{ 
rc = SQLSetParam(hstmt, (UWORD)(w+1), 
SQL_C_TCHAR, rgFields[ind].wSQLType, 
rgFields[ind].precision, rgFields[ind].scale, 
&lpd[w].data, 
&lpd[w].cb); 
RETCHECK(SQL_SUCCESS, rc,szSQLSETPARAM); 
} 
else 
{ 
rc = SQLBindParameter(hstmt, (UWORD)(w+1), 
SQL_PARAM_INPUT, 
SQL_C_TCHAR, rgFields[ind].wSQLType, 
rgFields[ind].precision, rgFields[ind].scale, 
&lpd[w].data, MAX_STRING_SIZE, 
&lpd[w].cb); 
RETCHECK(SQL_SUCCESS, rc,szSQLBINDPARAMETER); 
} 
} 
w++; 
cNumResSetCols=w; 
} 
 
if(fColNames)  
{  
/* the first time through, the insert*/ 
/* statement needs to be SQLPrepare'd*/ 
/* remove the "," at the end of the string*/ 
lpqt->szColNames[lstrlen(lpqt->szColNames) - 2] = TEXT('\0'); 
lpqt->szValues[lstrlen(lpqt->szValues) - 2] = TEXT('\0'); 
 
wsprintf(lpqt->sz,TEXT("insert into %s (%s) VALUES(%s)"), 
lpqt->szTableName, lpqt->szColNames, lpqt->szValues); 
 
//copy the insert statement, with the column names.  
//_ASSERTE(lstrlen(lpqt->sz) < MAX_STRING_SIZE); 
lstrcpy(szInsertStmt,lpqt->sz); 
 
//prepare the statement 
rc = SQLPrepare(hstmt, lpqt->sz, SQL_NTS); 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE)) 
goto InsertErrorRet; 
 
fColNames = FALSE; /* no more first times through */ 
} 
 
rc = SQLExecute(hstmt); /* insert a row */ 
 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLEXECUTE)) 
{ 
if (SQL_SUCCESS_WITH_INFO != rc)// BANDAID, normally would fail on S.W.I 
goto InsertErrorRet; 
} 
 
rc = SQLRowCount(hstmt, &sdw); 
RETCHECK(SQL_SUCCESS, rc,szSQLROWCOUNT); 
 
if(sdw != 1) /* the execute inserted 1 row */ 
DISPLAYERROR(szSQLROWCOUNT,TEXT("Insert single row")); 
 
/* FreeStmt SQL_CLOSE */ 
rc = SQLFreeStmt(hstmt, SQL_CLOSE); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT); 
} 
 
/* for the last row use SQLParamData and SQLPutData */ 
 
/* First check to see if the SQL_LEN_DATA_AT_EXEC macro is supported */ 
rc = SQLGetInfo(hdbc, SQL_NEED_LONG_DATA_LEN, lpqt->buf, (SWORD)sizeof(lpqt->buf), NULL); 
if(rc == SQL_SUCCESS) 
if(lpqt->buf[0] == TEXT('Y')) 
fLongData = TRUE; 
 
for(ind = 0, w = 0; ind < cTypes; ind++)  
{  
 
/* set all the params */ 
 
if(rgFields[ind].fAutoUpdate) 
continue; 
 
if(fLongData && ((rgFields[ind].wSQLType == SQL_LONGVARBINARY) ||  
(rgFields[ind].wSQLType == SQL_LONGVARCHAR))){ 
/* Make sure we don't exceed the max negative SDWORD value */ 
if(rgFields[ind].precision > (MAXSDWORD + SQL_LEN_DATA_AT_EXEC_OFFSET)) 
sdwArray[ind] = MINSDWORD - SQL_LEN_DATA_AT_EXEC_OFFSET; 
else 
sdwArray[ind] = SQL_LEN_DATA_AT_EXEC(rgFields[ind].precision); 
} 
else 
sdwArray[ind] = SQL_DATA_AT_EXEC; 
 
w++; 
if(!fBindParameter){ 
rc = SQLSetParam(hstmt, w, 
SQL_C_TCHAR, rgFields[ind].wSQLType, 
rgFields[ind].precision, rgFields[ind].scale, 
(LPTSTR)(UDWORD)ind, &sdwArray[ind]); 
RETCHECK(SQL_SUCCESS, rc,szSQLSETPARAM); 
} 
else{ 
rc = SQLBindParameter(hstmt, w, SQL_PARAM_INPUT, 
SQL_C_TCHAR, rgFields[ind].wSQLType, 
rgFields[ind].precision, rgFields[ind].scale, 
(LPTSTR)(((UDWORD)ind)+BIND_PARM_OFFSET), 0, &sdwArray[ind]); 
RETCHECK(SQL_SUCCESS, rc,szSQLBINDPARAMETER); 
} 
} 
 
*cColsSelected = w; 
 
rc = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS); 
if (!RETCHECK(SQL_NEED_DATA, rc,szSQLEXECDIRECT)) 
goto InsertErrorRet; 
 
 
for(ind = 0; ind <= cTypes; ind++)  
{ 
rc = SQLParamData(hstmt, &ptr); 
if(rc != SQL_NEED_DATA) 
break; 
 
pch = qtMakeData(cTypes, ind, &rgFields[(unsigned long)ptr-BIND_PARM_OFFSET], 
lpqt->szDataItem); 
 
if(*pch) { 
rc = SQLPutData(hstmt, pch, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLPUTDATA); 
} else { 
rc = SQLPutData(hstmt, (LPTSTR)IGNORED, SQL_NULL_DATA); 
RETCHECK(SQL_SUCCESS, rc,szSQLPUTDATA); 
} 
} 
   
RETCHECK(SQL_SUCCESS, rc,szSQLPARAMDATA); 
 
rc = SQLRowCount(hstmt, &sdw); 
RETCHECK(SQL_SUCCESS, rc,szSQLROWCOUNT); 
 
if(sdw != 1) 
DISPLAYERROR(szSQLROWCOUNT,TEXT("Insert single row")); 
 
rc = SQLFreeStmt(hstmt, SQL_RESET_PARAMS); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT); 
 
 
 
ReleaseMemory(sdwArray); 
 
return(FALSE); 
 
InsertErrorRet: 
 
ReleaseMemory(sdwArray); 
  
return(TRUE); 
 
} //BuildInsertStmt() 
 
 
//----------------------------------------------------------------------- 
//      Function:               FullDisconnect 
//----------------------------------------------------------------------- 
 
void  PASCAL FullDisconnect() 
{  
RETCODE rc=SQL_SUCCESS; 
 
/* SQLCancel has the same functionality as SQLFreeStmt w/ SQL_CLOSE*/ 
/*in a non-asynchronous environment */ 
 
rc = SQLCancel(hstmt); 
RETCHECK(SQL_SUCCESS, rc,szSQLCANCEL); 
 
FreeStmt(SQL_DROP); 
 
/* if the connection was made in the*/ 
/*test, it should be disconnected*/ 
/* in the test, otherwise it should be left connected */ 
 
rc = SQLDisconnect(hdbc); 
RETCHECK(SQL_SUCCESS, rc,szSQLDISCONNECT); 
 
rc = SQLFreeConnect(hdbc); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREECONNECT); 
 
rc = SQLFreeEnv(henv); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREEENV); 
 
 
} //FullDisconnect() 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               DropTable 
//----------------------------------------------------------------------- 
 
void  PASCAL DropTable(LPTSTR szTableName, BOOL fSilent) 
{ 
TCHARszBuff[100]; 
RETCODErc=SQL_ERROR; 
 
lstrcpy(szBuff,TEXT("drop table ")); 
lstrcat(szBuff, szTableName); 
 
rc = SQLExecDirect(hstmt, szBuff, SQL_NTS); 
 
if (!fSilent) 
{ 
if(!RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT)) 
szWrite(TEXT("Unable to drop table"), TRUE); 
} 
 
} //DropTable() 
 
 
 
//----------------------------------------------------------------------- 
//    Function:CleanUp 
//Purpose:To drop the table,disconnect from data source and 
//release memory. 
//----------------------------------------------------------------------- 
 
void  PASCAL CleanUp(DSTRUCT  *lpd,QTSTRUCT  *lpqt,FIELDINFO  *rgFields, 
LPTSTR szTableName,BOOL fSilent,LPTSTR szValidServer) 
{ 
 
DropTable(szTableName, fSilent); 
 
if(szValidServer) 
FullDisconnect(); 
 
ReleaseMemory(lpd); 
ReleaseMemory(lpqt); 
ReleaseMemory(rgFields); 
 
} //CleanUp() 
 
 
//----------------------------------------------------------------------- 
//      Function:               BindAllColumns 
//----------------------------------------------------------------------- 
 
BOOL  PASCAL BindAllColumns(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes, 
DSTRUCT  *lpd) 
{ 
//----------------------------------------------------------------------- 
//      Function:               BindAllColumns 
UWORDi, 
w; 
RETCODErc=SQL_SUCCESS; 
 
for(i = 0, w = 0; i < cTypes; i++)  
{ 
 
if(!qtMakeData(1, i,&rgFields[i],lpqt->szDataItem)) 
continue; 
 
w++; 
 
switch(rgFields[i].wSQLType)  
{ 
case SQL_INTEGER: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpd[i].sdword, IGNORED, &lpd[i].cb); 
break; 
case SQL_SMALLINT: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpd[i].sword, IGNORED, &lpd[i].cb); 
break; 
case SQL_FLOAT: 
case SQL_DOUBLE: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpd[i].sdouble, IGNORED, &lpd[i].cb); 
break; 
case SQL_REAL: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpd[i].sfloat, IGNORED, &lpd[i].cb); 
break; 
case SQL_DATE: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpd[i].date, IGNORED, &lpd[i].cb); 
break; 
case SQL_TIME: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpd[i].time, IGNORED, &lpd[i].cb); 
break; 
case SQL_TIMESTAMP: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpd[i].timestamp, IGNORED, &lpd[i].cb); 
break; 
case SQL_CHAR: 
case SQL_VARCHAR: 
case SQL_NUMERIC: 
case SQL_DECIMAL: 
default: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
lpd[i].data, MAX_STRING_SIZE, &lpd[i].cb); 
break; 
} 
 
if(!RETCHECK(SQL_SUCCESS, rc, szSQLBINDCOL)) 
return(FALSE); 
} 
 
return(TRUE); 
 
} //BindAllColumns() 
 
/*----------------------------------------------------------------------- 
 *      Function:               BindFetchColumns 
 *  Used for Checking data in Result sets from fetch calls. 
 *  Binds Binary data types as SQL_C_CHAR 
 *----------------------------------------------------------------------- */ 
 
BOOL  PASCAL BindFetchColumns(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes, 
DSTRUCT  *lpdFetch) 
{ 
UWORDi, 
w; 
RETCODErc=SQL_SUCCESS; 
 
for(i = 0, w = 0; i < cTypes; i++)  
{ 
 
if(!qtMakeData(0, i,&rgFields[i],lpqt->szDataItem)) 
continue; 
 
w++; 
 
switch(rgFields[i].wSQLType)  
{ 
case SQL_BIGINT: 
case SQL_INTEGER: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpdFetch[i].sdword, IGNORED, &lpdFetch[i].cb); 
break; 
case SQL_TINYINT: 
case SQL_SMALLINT: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpdFetch[i].sword, IGNORED, &lpdFetch[i].cb); 
break; 
case SQL_FLOAT: 
case SQL_DOUBLE: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpdFetch[i].sdouble, IGNORED, &lpdFetch[i].cb); 
break; 
case SQL_REAL: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpdFetch[i].sfloat, IGNORED, &lpdFetch[i].cb); 
break; 
case SQL_DATE: 
case SQL_TYPE_DATE: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpdFetch[i].date, IGNORED, &lpdFetch[i].cb); 
break; 
case SQL_TIME: 
case SQL_TYPE_TIME: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpdFetch[i].time, IGNORED, &lpdFetch[i].cb); 
break; 
case SQL_TIMESTAMP: 
case SQL_TYPE_TIMESTAMP: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
&lpdFetch[i].timestamp, IGNORED, &lpdFetch[i].cb); 
break; 
case SQL_BIT: 
case SQL_BINARY: 
case SQL_VARBINARY: 
case SQL_LONGVARBINARY: 
rc = SQLBindCol(hstmt, w, SQL_C_TCHAR, 
lpdFetch[i].data, MAX_STRING_SIZE, &lpdFetch[i].cb); 
break; 
case SQL_CHAR: 
case SQL_VARCHAR: 
case SQL_NUMERIC: 
case SQL_DECIMAL: 
default: 
rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, 
lpdFetch[i].data, MAX_STRING_SIZE, &lpdFetch[i].cb); 
break; 
} 
 
if(!RETCHECK(SQL_SUCCESS, rc, szSQLBINDCOL)) 
return(FALSE); 
} 
 
return(TRUE); 
 
} /*BindFetchColumns() */ 
 
//----------------------------------------------------------------------- 
//      Function:               TestMetaData 
//----------------------------------------------------------------------- 
 
void  PASCAL TestMetaData(lpSERVERINFO lpSI, QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes) 
{ 
SWORD    wNum; 
UWORD    w; 
UWORD    i; 
UDWORD   dwLen; 
RETCODErc=SQL_SUCCESS; 
SWORDwType; 
SWORDwNull; 
 
SelectFromTable(lpqt); 
 
for(i = 0, w = 0; i < cTypes; i++)  
{ 
dwLen = 0; 
wNum = 0; 
wNull = 0; 
 
/* information returned by SQLDescribeCol should match info */ 
/*used to create table */ 
 
if(!qtMakeData(1, i,&rgFields[i],lpqt->szDataItem)) 
continue; 
 
w++; 
rc = SQLDescribeCol(hstmt, w, lpqt->buf, 
MAX_STRING_SIZE, NULL, &wType, &dwLen, &wNum, &wNull); 
RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBECOL); 
 
/* verify that column name returned is column name created */ 
 
if(0 != lstrcmpi(rgFields[i].szFieldName, lpqt->buf)) 
DISPLAYERROR(szSQLDESCRIBECOL,TEXT("incorrect column name")); 
 
if(wType != rgFields[i].wSQLType) 
{ 
// For a 2.x driver, SQLGetTypeInfo result will be SQL_DATE, etc, 
// but 3.0 DM will convert SQLDescribeCol values to TYPE_DATE, ETC. 
if ((uDriverODBCVer < 3) &&  
((SQL_TYPE_DATE == wType && SQL_DATE == rgFields[i].wSQLType) || 
(SQL_TYPE_TIME == wType && SQL_TIME == rgFields[i].wSQLType) || 
(SQL_TYPE_TIMESTAMP == wType && SQL_TIMESTAMP == rgFields[i].wSQLType))) 
NULL; 
else 
DISPLAYERROR(szSQLDESCRIBECOL,TEXT("incorrect SQLType")); 
} 
 
if(dwLen != (UDWORD)rgFields[i].precision) 
DISPLAYERROR(szSQLDESCRIBECOL,TEXT("incorrect precision")); 
 
if(wNum != rgFields[i].scale) 
DISPLAYERROR(szSQLDESCRIBECOL,TEXT("incorrect scale")); 
 
if(wNull != rgFields[i].nullable && wNull != SQL_NULLABLE_UNKNOWN && 
rgFields[i].nullable != SQL_NULLABLE_UNKNOWN) 
{ 
DISPLAYERROR(szSQLDESCRIBECOL,TEXT("incorrect nullable")); 
} 
} 
 
FreeStmt(SQL_CLOSE); 
 
} //TestMetaData() 
 
 
//----------------------------------------------------------------------- 
//      Function:               RetrieveData 
//----------------------------------------------------------------------- 
 
void PASCAL RetrieveData(QTSTRUCT *lpqt,FIELDINFO *rgFields, 
UWORD cTypes,DSTRUCT *lpd) 
{ 
RETCODErc=SQL_SUCCESS; 
UWORDind, 
i; 
intnSame; 
LPTSTRpch=NULL; 
TCHARszNum[MAX_NUM_BUFFER];   /* used with _ttoi and itoa conversions */ 
TCHAR*stopstring=NULL; 
doubleNum=0, 
Num2=0; 
 
for(ind = 0; ;ind++)  
{ 
 
/* Get the data back */ 
rc = SQLFetch(hstmt); 
if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) 
break; 
 
for(i = 0; i < cTypes; i++)  
{  
/* make sure it's original data placed */ 
/* in that field/row location */ 
pch = qtMakeData(ind, i,&rgFields[i], lpqt->szDataItem); 
 
if(!pch) 
continue; 
 
if(!*pch) { 
if(lpd[i].cb != SQL_NULL_DATA) 
DISPLAYERROR(szRETDATA, TEXT("should have been NULL")); 
continue; 
} 
switch(rgFields[i].wSQLType)  
{ 
/* check the outlen and data*/ 
/* returned for each type. */ 
case SQL_INTEGER: 
if(lpd[i].cb != sizeof(SDWORD)) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
 
lstrcpy(szNum, pch); 
nSame = _ttol(szNum) == lpd[i].sdword; 
break; 
case SQL_SMALLINT: 
if(lpd[i].cb != sizeof(SWORD)) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
 
lstrcpy(szNum, pch); 
nSame = _ttoi(szNum) == lpd[i].sword; 
break; 
 
case SQL_FLOAT: 
case SQL_DOUBLE: 
if(lpd[i].cb != sizeof(SDOUBLE)) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
 
lstrcpy(szNum, pch); 
Num=_tcstod(szNum, &stopstring); 
nSame = Num - lpd[i].sdouble < 0.001 && Num - lpd[i].sdouble > -0.001; 
 
break; 
 
case SQL_REAL: 
if(lpd[i].cb != sizeof(SFLOAT)) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
 
lstrcpy(szNum, pch); 
Num=_tcstod(szNum, &stopstring); 
 
nSame = Num - lpd[i].sfloat < 0.001 && Num - lpd[i].sfloat > -0.001; 
break; 
 
case SQL_TINYINT: 
if(lpd[i].cb != sizeof(TCHAR)) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
 
lstrcpy(szNum, pch); 
nSame = (TCHAR)_ttoi(szNum) == (TCHAR)lpd[i].data[0]; 
break; 
 
case SQL_DECIMAL: 
case SQL_NUMERIC: 
if(lpd[i].cb > MAX_STRING_SIZE) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
 
if(lpd[i].cb > lstrlen(lpd[i].data)) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
 
{ 
TCHAR szNum2[MAX_NUM_BUFFER]; 
 
lstrcpy(szNum, pch); 
lstrcpy(szNum2, pch); 
Num=_tcstod(szNum, &stopstring); 
Num2=_tcstod(szNum2, &stopstring); 
 
nSame = Num - Num2 < 0.001 &&Num - Num2 > -0.001; 
} 
 
break; 
 
 
case SQL_VARCHAR: 
case SQL_LONGVARCHAR: 
if(lpd[i].cb > MAX_STRING_SIZE) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
 
if(lpd[i].cb > lstrlen(lpd[i].data)) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
 
nSame = !!_tcsstr(lpd[i].data, pch); 
 
break; 
 
case SQL_VARBINARY: 
case SQL_LONGVARBINARY: 
if(lpd[i].cb > MAX_STRING_SIZE) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
 
if(lpd[i].cb  * 2 != lstrlen(pch)) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
 
nSame = TRUE; /* not checking returned data for binary */ 
 
break; 
 
case SQL_CHAR: 
if(lpd[i].cb > MAX_STRING_SIZE && rc == SQL_SUCCESS) 
DISPLAYERROR(szRETDATA,TEXT("incorrect return code for outlen")); 
 
if(lpd[i].cb != rgFields[i].precision && rc == SQL_SUCCESS) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
 
nSame = !_tcsnccmp(lpd[i].data, pch, lstrlen(pch)); 
 
break; 
case SQL_BINARY: 
default: 
if(lpd[i].cb > MAX_STRING_SIZE && rc == SQL_SUCCESS) 
DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); 
nSame = TRUE; /* not checking returned data for binary */ 
} 
 
if(!nSame) 
DISPLAYERROR(szRETDATA, TEXT("invalid data")); 
} 
} 
 
RETCHECK(SQL_NO_DATA_FOUND, rc, szSQLFETCH); 
 
if(ind != cTypes + 1) 
DISPLAYERROR(szSQLFETCH, TEXT("Incorrect number of result rows")); 
 
rc = SQLFreeStmt(hstmt, SQL_CLOSE); 
RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT); 
 
rc = SQLFreeStmt(hstmt, SQL_UNBIND); 
RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT); 
 
rc = SQLFreeStmt(hstmt, SQL_RESET_PARAMS); 
RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT); 
 
} // RetrieveData() 
 
 
   
//----------------------------------------------------------------------- 
//      Function:               TestData 
//----------------------------------------------------------------------- 
 
void  PASCAL TestData(QTSTRUCT  *lpqt,FIELDINFO  *rgFields, 
UWORD cTypes,DSTRUCT  *lpd) 
{ 
 
/* bind all fields to a variable of the correct type for retreiving data */ 
if (!BindAllColumns(lpqt,rgFields,cTypes,lpd)) 
return; 
 
SelectFromTable(lpqt); 
 
RetrieveData(lpqt,rgFields,cTypes,lpd); 
 
} // TestData() 
 
 
//----------------------------------------------------------------------- 
//      Function:               CreateParamQuery 
//----------------------------------------------------------------------- 
 
void  PASCAL CreateParamQuery(QTSTRUCT *lpqt, FIELDINFO *rgFields,UWORD cTypes) 
{ 
RETCODErc=SQL_SUCCESS; 
UWORDi; 
LPTSTRpch=NULL; 
TCHARszQuery[MAX_QUERY_SIZE]; 
SDWORDsdw = SQL_DATA_AT_EXEC; 
UWORDw, 
ind; 
 
 
wsprintf(szQuery,TEXT("select %s from %s where "), lpqt->szColNames,lpqt->szTableName); 
 
 
for(i = 0, w = 0,ind=0; i < cTypes; i++)  
{ 
pch = qtMakeData(ind, i,&rgFields[i], lpqt->szDataItem); 
 
if ((rgFields[i].fSearchable == SQL_SEARCHABLE || 
rgFields[i].fSearchable == SQL_ALL_EXCEPT_LIKE) && 
pch && *pch)  
{ 
w++; 
 
switch(rgFields[i].wSQLType) 
{ 
case SQL_REAL: 
case SQL_FLOAT: 
case SQL_DOUBLE: 
wsprintf(&szQuery[lstrlen(szQuery)],TEXT("%s < ? + 1 and "), 
rgFields[i].szFieldName); 
break; 
default: 
wsprintf(&szQuery[lstrlen(szQuery)],TEXT("%s = ? and "), 
rgFields[i].szFieldName); 
} 
 
if(!fBindParameter) 
{ 
rc = SQLSetParam(hstmt, w, 
SQL_C_TCHAR, rgFields[i].wSQLType, 
rgFields[i].precision, rgFields[i].scale, 
(LPTSTR)(UDWORD)i, &sdw); 
RETCHECK(SQL_SUCCESS, rc,szSQLSETPARAM); 
} 
else 
{ 
rc = SQLBindParameter(hstmt, w, SQL_PARAM_INPUT, 
SQL_C_TCHAR, rgFields[i].wSQLType, 
rgFields[i].precision, rgFields[i].scale, 
(LPTSTR)((UDWORD)i+BIND_PARM_OFFSET), 0, &sdw); 
RETCHECK(SQL_SUCCESS, rc,szSQLBINDPARAMETER); 
} 
 
ind++; 
} 
} 
 
if (_tcsstr(szQuery,TEXT("and"))) 
{ 
/* remove the final "and " */ 
szQuery[lstrlen(szQuery) - 5] = TEXT('\0'); 
} 
 
lstrcpy(lpqt->szParamQuery, szQuery); 
 
} 
 
//----------------------------------------------------------------------- 
//      Function:               TestSearchedQuery 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSearchedQuery(QTSTRUCT  *lpqt,FIELDINFO  *rgFields, 
UWORD cTypes,DSTRUCT  *lpd,BOOL fBindParameter) 
{ 
RETCODErc=SQL_SUCCESS; 
UWORDi; 
LPTSTRpch=NULL; 
SDWORDsdw; 
UWORDw; 
UDWORDudw; 
UWORDind; 
 
 
wsprintf(lpqt->sz, TEXT("select %s from %s where "), lpqt->szColNames, 
lpqt->szTableName); 
 
    sdw = SQL_DATA_AT_EXEC; 
 
for(i = 0, w = 0,ind=0; i < cTypes; i++)  
{ 
pch = qtMakeData(ind, i,&rgFields[i], lpqt->szDataItem); 
 
if ((rgFields[i].fSearchable == SQL_SEARCHABLE || 
rgFields[i].fSearchable == SQL_ALL_EXCEPT_LIKE) && 
pch && *pch) { 
w++; 
switch(rgFields[i].wSQLType) { 
case SQL_REAL: 
case SQL_FLOAT: 
case SQL_DOUBLE: 
wsprintf(&lpqt->sz[lstrlen(lpqt->sz)], TEXT("%s < ? + 1 and "), 
rgFields[i].szFieldName); 
break; 
default: 
wsprintf(&lpqt->sz[lstrlen(lpqt->sz)], TEXT("%s = ? and "), 
rgFields[i].szFieldName); 
} 
 
if(!fBindParameter){ 
rc = SQLSetParam(hstmt, w, 
SQL_C_TCHAR, rgFields[i].wSQLType, 
rgFields[i].precision, rgFields[i].scale, 
(LPTSTR)(UDWORD)i, &sdw); 
RETCHECK(SQL_SUCCESS, rc, szSQLSETPARAM); 
} 
else{ 
rc = SQLBindParameter(hstmt, w, SQL_PARAM_INPUT, 
SQL_C_TCHAR, rgFields[i].wSQLType, 
rgFields[i].precision, rgFields[i].scale, 
(LPTSTR)((UDWORD)i+BIND_PARM_OFFSET), 0, &sdw); 
RETCHECK(SQL_SUCCESS, rc, szSQLBINDPARAMETER); 
} 
 
ind++; 
} 
} 
/* remove the final "and " */ 
lpqt->sz[lstrlen(lpqt->sz) - 5] = TEXT('\0'); 
lstrcpy(lpqt->szParamQuery, lpqt->sz); 
 
rc = SQLPrepare(hstmt, lpqt->sz, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc, szSQLPREPARE); 
 
rc = SQLExecute(hstmt); 
RETCHECK(SQL_NEED_DATA, rc, szSQLEXECUTE); 
 
udw = cTypes; 
 
for(i = 0; ; i++)  
{ 
rc = SQLParamData(hstmt, (PTR *)&udw); 
if(rc != SQL_NEED_DATA) 
break; 
 
if(udw-BIND_PARM_OFFSET < cTypes) 
pch = qtMakeData(cTypes, i,&rgFields[udw-BIND_PARM_OFFSET], lpqt->szDataItem); 
else 
DISPLAYERROR(szSQLPARAMDATA, TEXT("invalid rgbValue")); 
 
if(*pch)  
{ 
udw = lstrlen(pch); 
rc = SQLPutData(hstmt, pch, (SDWORD)lstrlen(pch)); 
RETCHECK(SQL_SUCCESS, rc, szSQLPUTDATA); 
}  
else 
{ 
rc = SQLPutData(hstmt, (LPTSTR)IGNORED, SQL_NULL_DATA); 
RETCHECK(SQL_SUCCESS, rc, szSQLPUTDATA); 
} 
} 
 
RETCHECK(SQL_SUCCESS, rc, szSQLPARAMDATA); 
 
for(i = 0;; i++)  
{ 
rc = SQLFetch(hstmt); 
 
if(rc != SQL_SUCCESS) 
break; 
} 
 
RETCHECK(SQL_NO_DATA_FOUND, rc, szSQLFETCH); 
 
/* should have gotten 1 row back */ 
 
if(i != 1) 
DISPLAYERROR(TEXT("Param/PutData"), TEXT("incorrect number of rows returned")); 
 
FreeStmt(SQL_CLOSE); 
 
} //TestSearchedQuery() 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestLargeQuery 
//----------------------------------------------------------------------- 
 
void  PASCAL TestLargeQuery(QTSTRUCT  *lpqt,FIELDINFO  *rgFields, 
UWORD cTypes,DSTRUCT  *lpd) 
{ 
RETCODErc=SQL_SUCCESS; 
UWORDind=0, 
i; 
LPTSTRpch=NULL; 
TCHARszQuery[2048]; 
 
 
/* > 1K query */ 
wsprintf(szQuery,TEXT("select %s from %s where "), lpqt->szColNames, 
lpqt->szTableName); 
 
for(i = 0; i < cTypes; i++)  
{ 
if (rgFields[i].fSearchable == SQL_SEARCHABLE || 
rgFields[i].fSearchable == SQL_ALL_EXCEPT_LIKE) 
break; 
} 
 
pch = qtMakeData(cTypes, 1, &rgFields[i], lpqt->szDataItem); 
while(lstrlen(szQuery) < 1024L)  
{ 
int li=lstrlen(szQuery); 
switch(rgFields[i].wSQLType)  
{ 
case SQL_REAL: 
case SQL_FLOAT: 
case SQL_DOUBLE: 
wsprintf(&szQuery[lstrlen(szQuery)],TEXT("%s < %s + 1 and "), 
rgFields[i].szFieldName, pch); 
break; 
default: 
wsprintf(&szQuery[lstrlen(szQuery)],TEXT("%s = %s%s%s and "), 
rgFields[i].szFieldName, rgFields[i].szPrefix, pch, rgFields[i].szSuffix); 
break; 
} 
} 
 
/* remove the final "and " */ 
szQuery[lstrlen(szQuery) - 5] = TEXT('\0'); 
 
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
if (RC_SUCCESSFUL(rc)) 
{ 
for(i = 0;; i++)  
{ 
rc = SQLFetch(hstmt); 
 
if(rc != SQL_SUCCESS) 
break; 
} 
 
RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH); 
 
/* should have gotten at least 1 row back */ 
 
if(i < 1) 
DISPLAYERROR(TEXT("> 1K query"),TEXT("incorrect number of rows returned")); 
 
} 
 
/* SQLFreeStmt with SQL_CLOSE to re-use the hstmt */ 
 
FreeStmt(SQL_CLOSE); 
 
} //TestLargeQuery() 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLTables 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLTables(QTSTRUCT  *lpqt) 
{ 
RETCODErc=SQL_SUCCESS; 
BOOLfFoundTable=FALSE; 
UWORDi; 
 
/* this call may return many tables, as  */ 
/* long as the one created earlier shows */ 
/* up it will pass. */ 
 
rc = SQLTables(hstmt, NULL, 0, NULL, 0,TEXT("q%"),SQL_NTS,TEXT("'TABLE'"), SQL_NTS);  
 
RETCHECK(SQL_SUCCESS, rc,szSQLTABLES); 
 
for(i = 0;; i++)  
{ 
rc = SQLFetch(hstmt); 
if(rc != SQL_SUCCESS) 
break; 
 
/* column 3 is tablename */ 
rc = SQLGetData(hstmt, 3, SQL_C_TCHAR, lpqt->sz, MAX_STRING_SIZE, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); /* should not overflow 
and return SQL_SUCCESS_WITH_INFO because the buffer is larger than the 
table name */ 
fFoundTable += 0 == lstrcmpi(lpqt->sz, lpqt->szTableName); 
} 
 
RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH); 
 
if(1 != fFoundTable) { 
DISPLAYERROR(szSQLTABLES,TEXT("table not found")); 
} 
 
FreeStmt(SQL_CLOSE); 
 
} //TestSQLTables() 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLSpecialCols 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLSpecialCols(QTSTRUCT  *lpqt) 
{ 
RETCODErc=SQL_SUCCESS; 
UWORDi; 
 
rc = SQLSpecialColumns(hstmt, SQL_BEST_ROWID, NULL, 0, NULL, 0, 
lpqt->szTableName, (SWORD)(lstrlen(lpqt->szTableName)), SQL_SCOPE_TRANSACTION, 
SQL_NULLABLE); 
RETCHECK(SQL_SUCCESS, rc,szSQLSPECIALCOLUMNS); 
 
for(i = 0;; i++) 
{ 
rc = SQLFetch(hstmt); 
if(rc != SQL_SUCCESS) 
break; 
} 
 
RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH); 
 
FreeStmt(SQL_CLOSE); 
 
} //TestSQLSpecialCols() 
 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               VerifyIndex 
//----------------------------------------------------------------------- 
 
void  PASCAL VerifyIndex(QTSTRUCT  *lpqt,UWORD fIndex) 
{ 
RETCODErc=SQL_SUCCESS; 
BOOLfFoundTable=FALSE; 
UWORDi; 
SDWORDsdw; 
 
rc = SQLStatistics(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, 
SQL_NTS, SQL_INDEX_ALL, SQL_ENSURE); 
RETCHECK(SQL_SUCCESS, rc,TEXT("SQLStatistics")); 
 
fFoundTable = 0; 
for(i = 0;; i++)  
{ 
rc = SQLFetch(hstmt); 
if(rc != SQL_SUCCESS) 
break; 
 
rc = SQLGetData(hstmt, 3, SQL_C_TCHAR, lpqt->sz, MAX_STRING_SIZE, 
&sdw); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); 
if (lstrcmpi(lpqt->sz, lpqt->szTableName) == 0) 
{ 
rc = SQLGetData(hstmt, 6, SQL_C_TCHAR, lpqt->sz, MAX_STRING_SIZE, 
&sdw); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); 
fFoundTable += 0 == lstrcmpi(lpqt->sz, lpqt->szDataItem); 
} 
} 
 
RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH); 
 
if(1 != fFoundTable && fIndex) 
DISPLAYERROR(TEXT("SQLStatistics"),TEXT("index not returned")); 
 
/* one row represents original table, the */ 
/* other represents the index */ 
if(i > 2 || i < 1)  
DISPLAYERROR(TEXT("SQLStatistics"),TEXT("too many rows")); 
 
FreeStmt(SQL_CLOSE); 
 
} //VerifyIndex() 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLStatistics 
//----------------------------------------------------------------------- 
 
BOOL  PASCAL TestSQLStatistics(QTSTRUCT  *lpqt,FIELDINFO  *rgFields, 
UWORD cTypes,DSTRUCT  *lpd,UWORD fIndex) 
{ 
RETCODErc=SQL_SUCCESS; 
UWORDi; 
 
lstrcpy(lpqt->szDataItem, lpqt->szTableName); 
lpqt->szDataItem[0] = TEXT('i'); 
for(i = 1; i < cTypes; i++) 
if(rgFields[i].wSQLType == SQL_INTEGER || 
rgFields[i].wSQLType == SQL_SMALLINT) 
break; 
if(i == cTypes) 
i = 0; 
 
lstrcpy(lpqt->buf, rgFields[i].szFieldName); 
wsprintf(lpqt->sz,TEXT("create unique index %s on %s (%s)"), 
lpqt->szDataItem, lpqt->szTableName, lpqt->buf); 
 
rc = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS); 
if(fIndex < 1) 
/* if this is minimal grammar, don't count on indexes being available */ 
fIndex = rc == SQL_SUCCESS; 
else 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
VerifyIndex(lpqt,fIndex); 
 
return(fIndex); 
 
} //TestSQLStatistics() 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestLikeQuery 
//----------------------------------------------------------------------- 
 
void  PASCAL TestLikeQuery(QTSTRUCT  *lpqt,FIELDINFO  *rgFields, 
UWORD cTypes,DSTRUCT  *lpd) 
{ 
RETCODErc=SQL_SUCCESS; 
UWORDi; 
SDWORDcbValue=0; 
 
for(i = 0; i < cTypes; i++)  
{ 
if(rgFields[i].fSearchable == SQL_LIKE_ONLY || 
rgFields[i].fSearchable == SQL_SEARCHABLE)  
{ 
lstrcpy(lpqt->buf, rgFields[i].szFieldName); 
break; 
} 
} 
 
if(i < cTypes)  
{ 
 
/* execute a query using like.  This query should return all records */ 
/* this query should return all rows in the table */ 
 
wsprintf(lpqt->sz,TEXT("select * from %s where %s not like 'a'"), lpqt->szTableName, 
lpqt->buf, lpqt->buf); 
rc = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
for(i = 0;; i++)  
{ 
rc = SQLFetch(hstmt); 
if(rc != SQL_SUCCESS) 
break; 
 
rc = SQLGetData(hstmt, 1, SQL_C_TCHAR, lpqt->sz, MAX_STRING_SIZE, 
&cbValue); 
if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) 
RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); 
} 
 
RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH); 
 
if(i != cTypes) 
DISPLAYERROR(TEXT("'LIKE' query"),TEXT("incorrect number of result rows")); 
 
} 
 
FreeStmt(SQL_CLOSE); 
 
} //TestLikeQuery() 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestLikeQuery 
//----------------------------------------------------------------------- 
 
void  PASCAL TestOJCap(QTSTRUCT  *lpqt) 
{ 
RETCODErc=SQL_SUCCESS; 
UDWORDudw; 
 
rc = SQLGetInfo(hdbc, (UWORD)SQL_OJ_CAPABILITIES, &udw, (SWORD)(sizeof(udw)), NULL); 
if(RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO)) 
{ 
udw &= ~(SQL_OJ_LEFT | SQL_OJ_RIGHT | SQL_OJ_FULL | SQL_OJ_NESTED| 
SQL_OJ_NOT_ORDERED | SQL_OJ_INNER | SQL_OJ_ALL_COMPARISON_OPS); 
if(udw) 
{ 
wsprintf(lpqt->buf,TEXT("Undefined flags return from SQLGetInfo(...SQL_OJ_CAPABILITIES...) = %lX"), udw); 
DISPLAYERROR(szSQLGETINFO, lpqt->buf); 
} 
} 
 
rc = SQLGetInfo(hdbc, SQL_OUTER_JOINS, lpqt->buf, MAX_STRING_SIZE, NULL); 
if(RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO)){ 
*lpqt->buf = toupper(*lpqt->buf); 
if((!_tcsnccmp(lpqt->buf,TEXT("Y"), 1)) && (!_tcsnccmp(lpqt->buf,TEXT("N"), 1))) 
DISPLAYERROR(szSQLGETINFO,TEXT("Driver returned an invalid value for SQLGetInfo(...SQL_OUTER_JOINS...).  The only valid values are \"Y\" and \"N\".")); 
} 
 
} //TestOJCap() 
 
 
/*----------------------------------------------------------------------- 
 *      Function:               TestExtendedFetch 
 *-----------------------------------------------------------------------*/ 
 
void  PASCAL TestExtendedFetch(QTSTRUCT  *lpqt, FIELDINFO  *rgFields, UWORD cTypes) 
{ 
RETCODErc=SQL_SUCCESS; 
WORDfLevel2 = FALSE; 
DWORDdwLen=0; 
SWORDfSqlType; 
SDWORDcbValue=0; 
UWORDiTableCol,row,iCol,uwRowSetSize; 
TCHARszQuery[MAX_STRING_SIZE], szColName[SMALLBUFF]; 
TCHAR*rgbValue; 
DSTRUCT*rgData; 
DSTRUCT*pDataBuf; 
BOOLfCol0Bound=TRUE; 
 
uwRowSetSize=5; /* Cinco seems like a good rowset size */ 
 
/* Only col which might not be bound but might not be AutoUpdateable is col 0 */ 
if(!qtMakeData(0, 0, &rgFields[0], szQuery)) 
fCol0Bound = FALSE; 
 
SelectFromTable(lpqt); 
 
rc = SQLBindCol(hstmt, 1, SQL_C_BINARY, lpqt->sz, MAX_BIND_ARRAY_ELEMENT, 
&cbValue); 
RETCHECK(SQL_SUCCESS, rc,szSQLBINDCOL); 
 
if (!Supported(SQL_API_SQLEXTENDEDFETCH))  
{ 
rc = SQLExtendedFetch(hstmt, SQL_FETCH_FIRST, IGNORED, NULL, NULL); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(szSQLEXTENDEDFETCH, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLEXTENDEDFETCH); 
 
FreeStmt(SQL_CLOSE); 
return; 
}  
 
rc = SQLGetStmtOption(hstmt,SQL_CURSOR_TYPE,&dwLen); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTOPTION); 
 
if(dwLen != SQL_CURSOR_FORWARD_ONLY) 
{ 
rc = SQLExtendedFetch(hstmt, SQL_FETCH_FIRST, IGNORED, NULL, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXTENDEDFETCH); 
} 
else 
{ 
rc = SQLExtendedFetch(hstmt, SQL_FETCH_FIRST, IGNORED, NULL, NULL); 
RETCHECK(SQL_ERROR, rc,szSQLEXTENDEDFETCH); 
} 
 
rc = SQLFreeStmt(hstmt, SQL_CLOSE); 
RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT); 
 
rc = SQLFreeStmt(hstmt, SQL_UNBIND); 
RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT); 
 
rc = SQLFreeStmt(hstmt, SQL_RESET_PARAMS); 
RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT); 
 
/* Allocate an area for ExtendedFetch to take place */ 
if (!(rgData = AllocateMemory(sizeof(DSTRUCT)*cTypes*uwRowSetSize))){ 
DISPLAYERROR(szSQLEXTENDEDFETCH,TEXT("Insufficient Memory Available")); 
return; 
} 
 
/* Allocate an area for test data */ 
if (!(rgbValue = AllocateMemory(MAX_STRING_SIZE))){ 
DISPLAYERROR(szSQLEXTENDEDFETCH,TEXT("Insufficient Memory Available")); 
ReleaseMemory(rgData); 
return; 
} 
 
/* Get column for "order by" clause: */ 
wsprintf(szQuery,TEXT("select %s from %s"),lpqt->szColNames, lpqt->szTableName); 
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); 
if((SQL_SUCCESS!=rc) && (SQL_SUCCESS_WITH_INFO!=rc)){ 
RETCHECK(SQL_SUCCESS_WITH_INFO, rc, szSQLEXECDIRECT); 
goto abortxfetch; 
} 
iCol=0; 
do{ 
iCol++; 
rc=SQLDescribeCol(hstmt, iCol, szColName, (SMALLBUFF*sizeof(TCHAR)),  
NULL, &fSqlType, NULL, NULL, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBECOL); 
} while(fSqlType!=SQL_CHAR && iCol<=cTypes); 
 
FreeStmt(SQL_CLOSE); 
if(iCol>cTypes){ 
DISPLAYERROR(szSQLEXTENDEDFETCH, TEXT("\t\t\tSelect-order by  Failed")); 
goto abortxfetch; 
} 
 
/* Set rowset size and set to row-wise binding:  */ 
rc = SQLSetStmtOption(hstmt, SQL_ROWSET_SIZE, (UDWORD)uwRowSetSize); 
if (SQL_SUCCESS != rc){ 
DISPLAYERROR(TEXT("ExtendedFetch...SQLSetStmtOption(Rowset_Size)"), 
TEXT("SQLSetStmtOption Failed")); 
GetErrors(henv, hdbc,hstmt); 
} 
rc = SQLSetStmtOption(hstmt, SQL_BIND_TYPE, (sizeof(DSTRUCT)*cTypes)); 
if (SQL_SUCCESS != rc){ 
DISPLAYERROR(TEXT("ExtendedFetch...SQLSetStmtOption(Bind_Type)"), 
TEXT("SQLSetStmtOption Failed")); 
GetErrors(henv, hdbc,hstmt); 
} 
 
if(SQL_SUCCESS != SelectFromTableFetch(lpqt, szColName)){ 
DISPLAYERROR(szSQLEXTENDEDFETCH, TEXT("\t\t\tSelect-order by  Failed")); 
goto abortxfetch; 
} 
if (!BindFetchColumns(lpqt, rgFields, cTypes, rgData)){ 
DISPLAYERROR(szSQLEXTENDEDFETCH, szSQLBINDCOL); 
goto abortxfetch; 
} 
/* Fetch into allocated area rowset to be tested */ 
rc = SQLExtendedFetch(hstmt, SQL_FETCH_NEXT, 1, NULL, NULL); 
if (SQL_SUCCESS != rc){ 
RETCHECK(SQL_SUCCESS, rc,szSQLEXTENDEDFETCH); 
DISPLAYERROR(szSQLEXTENDEDFETCH, TEXT("Fetch Failed")); 
goto abortxfetch; 
} 
 
rc = SQLFreeStmt(hstmt, SQL_CLOSE); 
RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT); 
 
rc = SQLFreeStmt(hstmt, SQL_UNBIND); 
RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT); 
 
/* Set rowset size to "1" to test each row of rowset independently:  */ 
rc = SQLSetStmtOption(hstmt, SQL_ROWSET_SIZE, (UDWORD)(1)); 
if (SQL_SUCCESS != rc){ 
DISPLAYERROR(TEXT("ExtendedFetch...SQLSetStmtOption(Rowset_Size)"), 
TEXT("SQLSetStmtOption Failed")); 
GetErrors(henv, hdbc,hstmt); 
} 
 
 /* Check data in all rows of rowset */  
if(SQL_SUCCESS != SelectFromTableFetch(lpqt, szColName)){ 
DISPLAYERROR(szSQLEXTENDEDFETCH, TEXT("\t\t\tSelect-order by  Failed")); 
goto abortxfetch; 
} 
  
// Need to change this loop if number of rows in table < uwRowSetSize 
for (row=0; row<uwRowSetSize; row++) 
{ 
SWORD iResultSetCol=0; 
if (SQL_SUCCESS != (rc = SQLFetch(hstmt))){ 
RETCHECK(SQL_SUCCESS, rc, szSQLFETCH); 
DISPLAYERROR(szSQLEXTENDEDFETCH, TEXT("Fetch Failed")); 
goto abortxfetch; 
} 
 
pDataBuf=rgData+row*cTypes; 
for (iTableCol=0; iTableCol<cTypes; iTableCol++) 
{ 
/* Ignore columns which aren't bound as they aren't in the result set */ 
if((!iTableCol && !fCol0Bound) || rgFields[iTableCol].fAutoUpdate) 
continue; 
 
iResultSetCol++; 
rc = SQLGetData(hstmt, iResultSetCol, SQL_C_TCHAR, rgbValue, MAX_STRING_SIZE, 
 &cbValue); 
if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) 
RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); 
 
if(!CheckDataResults(row, iTableCol, &rgFields[iTableCol], pDataBuf,cbValue,rgbValue)) 
{ 
wsprintf(lpqt->buf, TEXT("Data Check Failed, Row %d, Table Col %d, DataType %d (%s)"), 
row, iTableCol, rgFields[iTableCol].wSQLType, rgFields[iTableCol].szFieldName) ; 
szWrite(lpqt->buf,FALSE); 
rgbValue[MAX_STRING_SIZE-1]=TEXT('\0'); 
wsprintf(lpqt->buf, TEXT("Returned Data: (%s)"), rgbValue); 
DISPLAYERROR(TEXT("ExtendedFetch"),lpqt->buf); 
// goto abortxfetch; 
} 
} 
} 
 
abortxfetch: 
FreeStmt(SQL_CLOSE); 
FreeStmt(SQL_UNBIND); 
ReleaseMemory(rgData); 
ReleaseMemory(rgbValue); 
} /* TestExtendedFetch() */ 
 
 
 
 
/*------------------------------------------------------------------------------ 
 *      Function:       TestQuickRebind Feature  
 *      Purpose:        To test this specific feature, not the function(s) using it. 
 *      Synopsis: 
 *      An area large enough for 12 rows of QRDSTRUCTs will be created. There will  
 * be two rows of the result set per Rowset. Rowset 1 should be duplicated 
 * in rows 0,1 and 3,4, while Rowset 2 should be duplicated in rows 6,7 and 9,10.  
 * Thus, rows 0 and 3 will contain the first row of the result set, rows 1 and  
 * 4 will contain the second row of the result set, etc.  Rows 2, 5, 8, and 
 * 11 should have their preset condition of all zeroes remain unchanged. 
 * ----------------------------------------------------------------------------*/ 
 
void  PASCAL TestQuickRebind(QTSTRUCT * lpqt, FIELDINFO  *rgFields, UWORD cTypes, 
  DSTRUCT  *lpd) 
{ 
RETCODErc; 
UWORDrow,iCol,iRowset,uwRowsetSize,iRowsetRow,iTableCol; 
UDWORDudwRowSize; 
SWORDfSqlType; 
SDWORDsdwOffset; 
DSTRUCT*rgData, *pZeroRow; 
DSTRUCT*pCurrentRowData; 
TCHARszQuery[MAX_STRING_SIZE], szColName[SMALLBUFF]; 
SDWORDcbValue; 
TCHAR*rgbValue=NULL; 
BOOLfCol0Bound=TRUE; 
 
udwRowSize = sizeof(DSTRUCT)*cTypes; 
/* cNumResSetCols is set in BuildInsertStmt() */ 
uwRowsetSize = 5;/* uwRowsetSize rows per Rowset */ 
 
/* Only col which might not be bound but might not be AutoUpdateable is col 0 */ 
if(!qtMakeData(0, 0, &rgFields[0], szQuery)) 
fCol0Bound = FALSE; 
 
/* Allocate an area for QuickRebind to take place */ 
if (!(rgData = AllocateMemory(NUM_QUIKREBIND_ROWSETS*(uwRowsetSize+1)*udwRowSize) )){ 
DISPLAYERROR(szQUICKREBIND,TEXT("\t\t\tInsufficient Memory Available")); 
return; 
} 
 
/* Allocate an area for a row of zeroes to place between each Rowset. */ 
if (!(pZeroRow = AllocateMemory(udwRowSize) )){ 
DISPLAYERROR(szQUICKREBIND,TEXT("\t\t\tInsufficient Memory Available")); 
goto abortQuikRebind; 
} 
 
/* Allocate an area for test data */ 
if (!(rgbValue = AllocateMemory(MAX_STRING_SIZE))){ 
DISPLAYERROR(szSQLEXTENDEDFETCH,TEXT("Insufficient Memory Available")); 
goto abortQuikRebind; 
} 
 
ResetHstmt(&hstmt); 
 
/* Get column for "order by" clause: */ 
wsprintf(szQuery,TEXT("select %s from %s"),lpqt->szColNames, lpqt->szTableName); 
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); 
if((SQL_SUCCESS!=rc) && (SQL_SUCCESS_WITH_INFO!=rc)){ 
RETCHECK(SQL_SUCCESS_WITH_INFO, rc, szSQLEXECDIRECT); 
goto abortQuikRebind; 
} 
iCol=0; 
do{ 
iCol++; 
rc=SQLDescribeCol(hstmt, iCol, szColName, (SMALLBUFF*sizeof(TCHAR)),  
NULL, &fSqlType, NULL, NULL, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBECOL); 
} while(fSqlType!=SQL_CHAR && iCol<=cTypes); 
 
FreeStmt(SQL_CLOSE); 
if(iCol>=cTypes){ 
DISPLAYERROR(szQUICKREBIND, TEXT("\t\t\tSelect-order by  Failed")); 
goto abortQuikRebind; 
} 
 
/* Set to row-wise binding and set Rowset size to uwRowsetSize:  */ 
rc = SQLSetStmtAttr(hstmt,SQL_ATTR_ROW_BIND_TYPE,(PTR)udwRowSize,SQL_IS_INTEGER); 
if (SQL_SUCCESS != rc){ 
_tcscpy(lpqt->buf,TEXT("\t\t\tQuick Rebind FAILED...SQLSetDescField(Bind_Type)")); 
szWrite(lpqt->buf, TRUE); 
goto abortQuikRebind; 
} 
rc = SQLSetStmtAttr(hstmt,SQL_ATTR_ROW_ARRAY_SIZE,(PTR)uwRowsetSize,SQL_IS_INTEGER); 
if (SQL_SUCCESS != rc){ 
DISPLAYERROR(szQUICKREBIND,TEXT("\t\t\tSetStmtAttr(Rowset Size)")); 
goto abortQuikRebind; 
} 
 
/* Define area storing Quikrebind offset value: */ 
rc = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, &sdwOffset, SQL_IS_POINTER); 
if (SQL_SUCCESS != rc){ 
if(FindError(SQL_HANDLE_STMT,szHYC00)){ 
_tcscpy(lpqt->buf,TEXT("\t\t\tQuickRebind Not Supported")); 
szWrite(lpqt->buf, TRUE); 
goto abortQuikRebind; 
} 
_tcscpy(lpqt->buf,TEXT("\t\t\tQuick Rebind FAILED...QuickRebind Not Functional")); 
szWrite(lpqt->buf, TRUE); 
goto abortQuikRebind; 
} 
 
if(SQL_SUCCESS != SelectFromTableFetch(lpqt, szColName)){ 
DISPLAYERROR(szQUICKREBIND, TEXT("\t\t\tSelect-order by  Failed")); 
goto abortQuikRebind; 
} 
  
if (!BindFetchColumns(lpqt, rgFields, cTypes, rgData)){ 
DISPLAYERROR(szQUICKREBIND,szSQLBINDCOL); 
goto abortQuikRebind; 
} 
 
/* Test quick rebind feature with two pairs of Rowsets, all * 
 * rowsets separated by a row of zeroes:                    */ 
for (iRowset=0; iRowset<=1; iRowset++) 
{ 
if(iRowset) 
if(SQL_SUCCESS != SelectFromTableFetch(lpqt, szColName)){ 
DISPLAYERROR(szQUICKREBIND, TEXT("\t\t\tSelect-order by  Failed")); 
goto abortQuikRebind; 
} 
  
/* Set offset value (to 0 or 1  * uwRowsetSize * udwRowSize) for 1st rowset */ 
sdwOffset = iRowset*((1+uwRowsetSize)*udwRowSize); 
 
/* Fetch rowset into desired area */ 
rc = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 1); 
if (SQL_SUCCESS != rc){ 
ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_SUCCESS, rc, szSQLFETCHSCROLL); 
DISPLAYERROR(szQUICKREBIND,TEXT("Fetch Failed")); 
goto abortQuikRebind; 
}                                                                                                                                                                 
 
/* Set offset value (to 2 or 3 * uwRowsetSize * udwRowSize) for 2nd rowset */ 
sdwOffset = (iRowset+2)*(1+uwRowsetSize)*udwRowSize; 
 
rc = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 1); 
if (SQL_SUCCESS != rc){ 
ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_SUCCESS, rc, szSQLFETCHSCROLL); 
DISPLAYERROR(szQUICKREBIND,TEXT("Fetch Failed")); 
goto abortQuikRebind; 
} 
FreeStmt(SQL_CLOSE); 
} 
 
rc = SQLFreeStmt(hstmt, SQL_UNBIND); 
RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT); 
 
rc = SQLSetStmtAttr(hstmt,SQL_ATTR_ROW_ARRAY_SIZE,(PTR)1,SQL_IS_INTEGER); 
if (SQL_SUCCESS != rc){ 
DISPLAYERROR(szQUICKREBIND,TEXT("\t\t\tSetStmtAttr(Rowset Size)")); 
goto abortQuikRebind; 
} 
 
/* Check stored values: */ 
for (iRowset=0; iRowset<=1; iRowset++) 
{ 
if(SQL_SUCCESS != SelectFromTableFetch(lpqt, szColName)){ 
DISPLAYERROR(szQUICKREBIND, TEXT("\t\t\tSelect-order by  Failed")); 
goto abortQuikRebind; 
} 
  
/* First Rowset starts either in Allocated Row 0 or 3 */ 
iRowsetRow= iRowset*(1+uwRowsetSize);   
//for (row=0; row<NUM_QUIKREBIND_ROWSETS  ;row++,iRowsetRow++) 
for (row=0; row<(uwRowsetSize*2)  ;row++,iRowsetRow++) 
{ 
UWORD iResultSetCol=0; 
if(row==uwRowsetSize)      
iRowsetRow+= 2+uwRowsetSize; /* Jump to 2nd Rowset */ 
 
/* Don't check data in "zero" row, * 
 * the spacer row between rowsets:*/ 
if(iRowsetRow%(1+uwRowsetSize) == uwRowsetSize) 
continue; 
 
/* Fetch next rowset */ 
rc = SQLFetch(hstmt); 
if (SQL_SUCCESS != rc){ 
ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_SUCCESS, rc, szSQLFETCH); 
DISPLAYERROR(szQUICKREBIND,TEXT("Fetch Failed")); 
goto abortQuikRebind; 
}                       
 
pCurrentRowData = rgData+iRowsetRow*cTypes; 
for(iTableCol=0; iTableCol<cTypes; iTableCol++) 
{ 
/* Ignore columns which aren't bound as they aren't in the result set */ 
if((!iTableCol && !fCol0Bound) || rgFields[iTableCol].fAutoUpdate) 
continue; 
 
iResultSetCol++; 
rc = SQLGetData(hstmt, iResultSetCol, SQL_C_TCHAR, rgbValue, MAX_STRING_SIZE, 
&cbValue); 
if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) 
RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); 
 
if(!CheckDataResults(row, iTableCol, &rgFields[iTableCol], pCurrentRowData,cbValue,rgbValue)) 
{ 
wsprintf(lpqt->buf, TEXT("Data Check Failed, Row %d, Table Col %d, DataType %d (%s)"), 
row, iTableCol, rgFields[iTableCol].wSQLType, rgFields[iTableCol].szFieldName) ; 
szWrite(lpqt->buf,FALSE); 
rgbValue[MAX_STRING_SIZE-1]=TEXT('\0'); 
wsprintf(lpqt->buf, TEXT("Returned Data: (%s)"), rgbValue); 
DISPLAYERROR(szQUICKREBIND,lpqt->buf); 
goto abortQuikRebind;  
} 
}/* end for(iTableCol) */ 
} /* end for(row)  */ 
FreeStmt(SQL_CLOSE); 
} /* end for (iRowset)  */ 
 
/* Check Unused memory areas:    */ 
for (iRowsetRow=uwRowsetSize; iRowsetRow<NUM_QUIKREBIND_ROWSETS*(uwRowsetSize+1);  ) 
{ 
pCurrentRowData = rgData+iRowsetRow*cTypes; 
if(memcmp(pCurrentRowData, pZeroRow, udwRowSize)) 
DISPLAYERROR(szQUICKREBIND, 
TEXT("Unused memory areas altered after Quick Rebind.")); 
iRowsetRow+=(uwRowsetSize+1); 
}                                                         
   
 
abortQuikRebind: 
ResetHstmt(&hstmt); 
if (rgbValue)                              
ReleaseMemory(rgbValue); 
if (pZeroRow)                              
ReleaseMemory(pZeroRow); 
ReleaseMemory(rgData); 
 
} /* TestQuickRebind() */ 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLForeignKeys 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLForeignKeys(QTSTRUCT  *lpqt) 
{ 
RETCODE rc=SQL_SUCCESS; 
 
if (!Supported(SQL_API_SQLFOREIGNKEYS)) 
{ 
rc = SQLForeignKeys(hstmt, NULL, 0, NULL, 0, lpqt->szTableName,  
SQL_NTS, NULL, 0, NULL, 0, NULL, 0); 
 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(szSQLFOREIGNKEYS, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLFOREIGNKEYS); 
} 
else 
{ 
rc = SQLForeignKeys(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, 
SQL_NTS, NULL, 0, NULL, 0, NULL, 0); 
 
RETCHECK(SQL_SUCCESS, rc,szSQLFOREIGNKEYS); 
 
while(rc == SQL_SUCCESS)  
rc = SQLFetch(hstmt); 
 
RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH); 
 
FreeStmt(SQL_CLOSE); 
 
} 
 
} //TestSQLForeignKeys() 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLBrowseConnect 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLBrowseConnect(lpSERVERINFO lpSI) 
{ 
RETCODErc=SQL_SUCCESS; 
UWORDcMaxConnections=0; 
TCHARszBCString[40]; 
TCHARszDSN[40]; 
HDBChdbcb=NULL; 
 
AllocHdbc(&hdbcb); 
 
rc = SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, &cMaxConnections, sizeof(int), NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); 
 
if(cMaxConnections != 1)  
{ 
lstrcpy(szBCString,TEXT("DSN=")); 
lstrcat(szBCString, lpSI->szValidServer0); 
 
if(lpSI->szValidServer0[0] == 0) 
{ 
rc = SQLGetInfo(hdbc, SQL_DATA_SOURCE_NAME, &szDSN, 40, NULL); 
lstrcat(szBCString, szDSN); 
} 
 
if(!Supported(SQL_API_SQLBROWSECONNECT)) 
{ 
HDBC thdbc=NULL; 
 
rc = SQLBrowseConnect(hdbcb, szBCString, SQL_NTS, NULL, 0, NULL); 
thdbc = hdbc; 
hdbc = hdbcb; 
if(!FindError(SQL_HANDLE_DBC,szIM001)) 
DISPLAYERROR(szSQLBROWSECONNECT, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLBROWSECONNECT); 
hdbc = thdbc; 
 
rc = SQLFreeConnect(hdbcb); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREECONNECT); 
 
} 
else 
{ 
rc = SQLBrowseConnect(hdbcb, szBCString, SQL_NTS, NULL, 0, NULL); 
RETCHECK(SQL_NEED_DATA, rc,szSQLBROWSECONNECT); 
 
rc = SQLDisconnect(hdbcb); 
RETCHECK(SQL_SUCCESS, rc,szSQLDISCONNECT); 
rc = SQLFreeConnect(hdbcb); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREECONNECT); 
} 
} 
 
} //TestSQLBrowseConnect() 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLDataSources 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLDataSources() 
{ 
RETCODE rc=SQL_SUCCESS; 
 
if (!Supported( SQL_API_SQLDATASOURCES)) 
{ 
rc = SQLDataSources(henv, SQL_FETCH_FIRST, NULL, 0, NULL, NULL, 0, NULL); 
 
if(!FindError(SQL_HANDLE_ENV,szIM001)) 
DISPLAYERROR(TEXT("SQLDataSources"), szNotSupported); 
 
RETCHECK(SQL_ERROR, rc,TEXT("SQLDataSources")); 
}  
else  
{ 
rc = SQLDataSources(henv, SQL_FETCH_FIRST, NULL, 0, NULL, NULL, 0, NULL); 
RETCHECK(SQL_SUCCESS, rc,TEXT("SQLDataSources")); 
} 
 
} //TestSQLDataSources() 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLDataSources 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLDrivers() 
{ 
RETCODE rc=SQL_SUCCESS; 
 
if(!Supported( SQL_API_SQLDRIVERS))  
{ 
rc = SQLDrivers(henv, SQL_FETCH_FIRST, NULL, 0, NULL, NULL, 0, NULL); 
if(!FindError(SQL_HANDLE_ENV,szIM001)) 
DISPLAYERROR(TEXT("SQLDrivers"), szNotSupported); 
RETCHECK(SQL_ERROR, rc,TEXT("SQLDataSources")); 
} 
else 
{ 
rc = SQLDrivers(henv, SQL_FETCH_FIRST, NULL, 0, NULL, NULL, 0, NULL); 
if(rc != SQL_SUCCESS) 
RETCHECK(SQL_SUCCESS_WITH_INFO, rc,TEXT("SQLDrivers")); 
} 
 
} //TestSQLDrivers() 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLMoreResults 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLMoreResults(QTSTRUCT  *lpqt) 
{ 
RETCODE rc=SQL_SUCCESS; 
 
if(!Supported( SQL_API_SQLMORERESULTS))  
{ 
SelectFromTable(lpqt); 
 
rc = SQLMoreResults(hstmt); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(TEXT("SQLMoreResults"), szNotSupported); 
RETCHECK(SQL_ERROR, rc,TEXT("SQLMoreResults")); 
} 
else 
{ 
SelectFromTable(lpqt); 
 
rc = SQLMoreResults(hstmt); 
RETCHECK(SQL_NO_DATA_FOUND, rc,TEXT("SQLMoreResults")); 
} 
 
FreeStmt(SQL_CLOSE); 
 
} //TestSQLMoreResults() 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLMoreResults 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLNativeSQL(QTSTRUCT  *lpqt) 
{ 
RETCODErc=SQL_SUCCESS; 
TCHARszQuery[XLARGEBUFF]; 
 
wsprintf(szQuery,TEXT("select * from %s were 0 > 1"),lpqt->szTableName); 
 
if(!Supported( SQL_API_SQLNATIVESQL)) 
{ 
rc = SQLNativeSql(hdbc, szQuery, SQL_NTS, NULL, 0, NULL); 
if(!FindError(SQL_HANDLE_DBC,szIM001)) 
DISPLAYERROR(TEXT("SQLNativeSql"), szNotSupported); 
RETCHECK(SQL_ERROR, rc,TEXT("SQLNativeSql")); 
} 
else  
{ 
rc = SQLNativeSql(hdbc, szQuery, SQL_NTS, NULL, 0, NULL); 
RETCHECK(SQL_SUCCESS, rc,TEXT("SQLNativeSql")); 
} 
 
FreeStmt(SQL_CLOSE); 
 
} //TestSQLNativeSQL() 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLDescribeParam 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLDescribeParam(QTSTRUCT  *lpqt) 
{ 
RETCODE rc=SQL_SUCCESS; 
 
rc = SQLPrepare(hstmt, lpqt->szParamQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE); 
 
if(!Supported( SQL_API_SQLDESCRIBEPARAM))  
{ 
rc = SQLPrepare(hstmt, lpqt->szParamQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE); 
rc = SQLDescribeParam(hstmt, 1, NULL, NULL, NULL, NULL); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(szSQLDESCRIBEPARAM, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLDESCRIBEPARAM); 
} 
else 
{ 
rc = SQLPrepare(hstmt, lpqt->szParamQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE); 
rc = SQLDescribeParam(hstmt, 1, NULL, NULL, NULL, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBEPARAM); 
} 
 
FreeStmt(SQL_CLOSE); 
 
} //TestSQLDescribeParam() 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLNumParams 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLNumParams(QTSTRUCT  *lpqt) 
{ 
RETCODE rc=SQL_SUCCESS; 
 
rc = SQLPrepare(hstmt, lpqt->szParamQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE); 
 
if(!Supported( SQL_API_SQLNUMPARAMS))  
{ 
rc = SQLNumParams(hstmt, NULL); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(szSQLNUMPARAMS, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLNUMPARAMS); 
} 
else 
{ 
rc = SQLNumParams(hstmt, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLNUMPARAMS); 
} 
 
FreeStmt(SQL_CLOSE); 
 
} //TestSQLNumParams() 
 
 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLParamOptions 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLParamOptions(QTSTRUCT *lpqt) 
{ 
RETCODE rc=SQL_SUCCESS; 
 
rc = SQLPrepare(hstmt, lpqt->szParamQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE); 
 
if(!Supported( SQL_API_SQLPARAMOPTIONS))  
{ 
rc = SQLParamOptions(hstmt, 1, NULL); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(szSQLPARAMOPTIONS, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLPARAMOPTIONS); 
} 
else 
{ 
rc = SQLParamOptions(hstmt, 1, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLPARAMOPTIONS); 
} 
 
FreeStmt(SQL_CLOSE); 
 
} //TestSQLParamOptions() 
 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLPrimaryKeys 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLPrimaryKeys(QTSTRUCT *lpqt) 
{ 
RETCODE rc=SQL_SUCCESS; 
 
if (!Supported( SQL_API_SQLPRIMARYKEYS)) 
{ 
rc = SQLPrimaryKeys(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(szSQLPRIMARYKEYS, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLPRIMARYKEYS); 
} 
else 
{ 
rc = SQLPrimaryKeys(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLPRIMARYKEYS); 
while(rc == SQL_SUCCESS)  
rc = SQLFetch(hstmt); 
 
RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH); 
 
FreeStmt(SQL_CLOSE); 
 
} 
 
} //TestSQLPrimaryKeys() 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLProcedureColumns 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLProcedureColumns(QTSTRUCT  *lpqt) 
{ 
RETCODE rc=SQL_SUCCESS; 
 
if(!Supported( SQL_API_SQLPROCEDURECOLUMNS))  
{ 
rc = SQLProcedureColumns(hstmt, NULL, 0, NULL, 0, NULL, 0, NULL, 0); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(TEXT("SQLProcedureColumns"), szNotSupported); 
RETCHECK(SQL_ERROR, rc,TEXT("SQLProcedureColumns")); 
} 
else  
{ 
rc = SQLProcedureColumns(hstmt, NULL, 0, NULL, 0, NULL, 0, NULL, 0); 
RETCHECK(SQL_SUCCESS, rc,TEXT("SQLProcedureColumns")); 
while(rc == SQL_SUCCESS) 
rc = SQLFetch(hstmt); 
 
RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH); 
 
FreeStmt(SQL_CLOSE); 
} 
 
} //TestSQLProcedureColumns() 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLProcedures 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLProcedures() 
{ 
RETCODE rc=SQL_SUCCESS; 
 
if(!Supported( SQL_API_SQLPROCEDURES))  
{ 
rc = SQLProcedures(hstmt, NULL, 0, NULL, 0, NULL, 0); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(TEXT("SQLProcedures"), szNotSupported); 
RETCHECK(SQL_ERROR, rc,TEXT("SQLProcedures")); 
} 
else 
{ 
rc = SQLProcedures(hstmt, NULL, 0, NULL, 0, NULL, 0); 
RETCHECK(SQL_SUCCESS, rc,TEXT("SQLProcedures")); 
while(rc == SQL_SUCCESS) 
rc = SQLFetch(hstmt); 
RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH); 
 
FreeStmt(SQL_CLOSE); 
} 
 
} //TestSQLProcedures() 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLTablePrivileges 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLTablePrivileges() 
{ 
RETCODE rc=SQL_SUCCESS; 
 
if(!Supported( SQL_API_SQLTABLEPRIVILEGES))  
{ 
rc = SQLTablePrivileges(hstmt, NULL, 0, NULL, 0, NULL, 0); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(TEXT("SQLTablePrivileges"), szNotSupported); 
RETCHECK(SQL_ERROR, rc,TEXT("SQLTablePrivileges")); 
} 
else 
{ 
rc = SQLTablePrivileges(hstmt, NULL, 0, NULL, 0, NULL, 0); 
RETCHECK(SQL_SUCCESS, rc,TEXT("SQLTablePrivileges")); 
while(rc == SQL_SUCCESS)  
rc = SQLFetch(hstmt); 
 
RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH); 
 
FreeStmt(SQL_CLOSE); 
} 
 
} //TestSQLTablePrivileges() 
 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLColumnPrivileges 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLColumnPrivileges(QTSTRUCT  *lpqt) 
{ 
RETCODE rc=SQL_SUCCESS; 
 
if(!Supported( SQL_API_SQLCOLUMNPRIVILEGES))  
{ 
rc = SQLColumnPrivileges(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS, 
NULL, 0); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(TEXT("SQLColummPrivileges"), szNotSupported); 
RETCHECK(SQL_ERROR, rc,TEXT("SQLColumnPrivileges")); 
}  
else 
{ 
rc = SQLColumnPrivileges(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS, 
NULL, 0); 
RETCHECK(SQL_SUCCESS, rc,TEXT("SQLColumnPrivileges")); 
while(rc == SQL_SUCCESS) 
rc = SQLFetch(hstmt); 
 
RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH); 
 
FreeStmt(SQL_CLOSE); 
} 
 
} // TestSQLColumnPrivileges() 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestSQLSetScrollOptions 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSQLSetScrollOptions() 
{ 
RETCODErc=SQL_SUCCESS; 
UWORDi, 
j; 
UDWORDfSupportedOpt; 
UDWORDfSupportedCon; 
TCHARszState[100]=TEXT(""), 
szErrMsg[XLARGEBUFF]=TEXT(""); 
 
FreeStmt(SQL_CLOSE); 
 
if(!Supported( SQL_API_SQLSETSCROLLOPTIONS))  
{ 
rc = SQLSetScrollOptions(hstmt, SQL_CONCUR_READ_ONLY, SQL_SCROLL_FORWARD_ONLY, 
1); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(szSQLSETSCROLLOPTIONS, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLSETSCROLLOPTIONS); 
}  
else 
{ 
rc = SQLGetInfo(hdbc, SQL_SCROLL_CONCURRENCY, &fSupportedCon, 4, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); 
rc = SQLGetInfo(hdbc, SQL_SCROLL_OPTIONS, &fSupportedOpt, 4, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); 
 
for(i = 0; i < sizeof(OptionList) / sizeof(SUPPORTOPTINFO); i ++)  
{ 
for(j = 0; j < sizeof(ConcurList) / sizeof(SUPPORTCONCURINFO); j++)  
{ 
if(fSupportedOpt & OptionList[i].Support && fSupportedCon & ConcurList[j].Support)  
{ 
if(!((ConcurList[j].Option == SQL_CONCUR_VALUES) && ((lpSI->vCursorLib ==  
SQL_CUR_USE_IF_NEEDED) || (lpSI->vCursorLib == SQL_CUR_USE_ODBC)))) 
{ 
rc = SQLSetScrollOptions(hstmt, ConcurList[j].Option,OptionList[i].Option, 1); 
RETCHECK(SQL_SUCCESS, rc,szSQLSETSCROLLOPTIONS); 
} 
 
} 
} 
} 
} 
 
FreeStmt(SQL_CLOSE); 
 
} //TestSQLSetScrollOptions() 
 
 
//----------------------------------------------------------------------------- 
//Function:  TestConnectAttr 
//----------------------------------------------------------------------------- 
 
VOID PASCAL TestConnectAttr(HDBC hdbc,SDWORD fAttribute, UDWORD rgbValue,LPTSTR lpAttr,BOOL fReadOnlyAttr) 
{ 
RETCODErc=SQL_SUCCESS; 
TCHARszBuff[LARGEBUFF]=TEXT(""); 
UDWORDpvParam=0; 
RETCODErcExp=fReadOnlyAttr ? SQL_ERROR : SQL_SUCCESS; 
 
rc = SQLSetConnectAttr(hdbc,fAttribute,(PTR)rgbValue,sizeof(rgbValue)); 
 
if(!FindError(SQL_HANDLE_DBC,szHYC00)) 
{ 
 
RETCHECK(rcExp,rc,szSQLSETCONNECTATTR); 
 
rc = SQLGetConnectAttr(hdbc,fAttribute,&pvParam,sizeof(pvParam),NULL); 
 
if(!FindError(SQL_HANDLE_DBC,szHYC00)) 
{ 
RETCHECK(SQL_SUCCESS,rc,szSQLGETCONNECTATTR); 
 
if(!fReadOnlyAttr && (pvParam != rgbValue)) 
{ 
wsprintf(szBuff,TEXT("%s returned incorrect value"),lpAttr); 
DISPLAYERROR(szSQLGETCONNECTATTR,szBuff); 
} 
} 
else 
RETCHECK(SQL_ERROR,rc,szSQLGETCONNECTATTR); 
} 
else 
RETCHECK(SQL_ERROR,rc,szSQLSETCONNECTATTR);  
 
} //TestConnectAttr() 
 
 
//----------------------------------------------------------------------------- 
//Function:  TestSQLSetConnectAttr 
//     This function tests both SQLSetConnectAttr and SQLGetConnectAttr 
//----------------------------------------------------------------------------- 
 
void  PASCAL TestSQLSetConnectAttr() 
{ 
RETCODE rc = SQL_SUCCESS; 
UDWORDpvParam; 
UWORDrgbValue; 
BOOLfSupportSetConnectAttr = TRUE; 
BOOLfSupportGetConnectAttr = TRUE; 
 
//make sure these APIs are supported before testing 
if(!Supported(SQL_API_SQLSETCONNECTATTR)) 
{ 
rgbValue = SQL_MODE_READ_WRITE; 
fSupportSetConnectAttr = FALSE; 
rc = SQLSetConnectAttr(hdbc,SQL_ACCESS_MODE,&rgbValue,sizeof(rgbValue)); 
if(!FindError(SQL_HANDLE_DBC,szIM001)) 
DISPLAYERROR(szSQLSETCONNECTATTR,TEXT("did not return Not supported message")); 
RETCHECK(SQL_ERROR,rc,szSQLSETCONNECTATTR); 
} 
 
if(!Supported(SQL_API_SQLGETCONNECTATTR)) 
{ 
fSupportGetConnectAttr = FALSE; 
rc = SQLGetConnectAttr(hdbc,SQL_ACCESS_MODE,&pvParam,sizeof(pvParam),NULL); 
if(!FindError(SQL_HANDLE_DBC,szIM001)) 
DISPLAYERROR(szSQLGETCONNECTATTR,TEXT("did not return Not supported message")); 
RETCHECK(SQL_ERROR,rc,szSQLGETCONNECTATTR); 
} 
 
if(fSupportSetConnectAttr && (!fSupportGetConnectAttr)) 
{ 
//test SQL_ACCESS_MODE 
rgbValue = SQL_MODE_READ_WRITE; 
rc = SQLSetConnectAttr(hdbc,SQL_ACCESS_MODE,&rgbValue,sizeof(rgbValue)); 
if(!FindError(SQL_HANDLE_DBC,szHYC00)) 
RETCHECK(SQL_SUCCESS,rc,szSQLSETCONNECTATTR); 
else 
RETCHECK(SQL_ERROR,rc,szSQLSETCONNECTATTR); 
//test SQL_AUTOCOMMIT 
rgbValue = SQL_AUTOCOMMIT_ON; 
rc = SQLSetConnectAttr(hdbc,SQL_AUTOCOMMIT,&rgbValue,sizeof(rgbValue)); 
if(!FindError(SQL_HANDLE_DBC,szHYC00)) 
RETCHECK(SQL_SUCCESS,rc,szSQLSETCONNECTATTR); 
else 
RETCHECK(SQL_ERROR,rc,szSQLSETCONNECTATTR); 
//test SQL_LOGIN_TIMEOUT 
//the choice of 15 seconds for timeout is arbitrary 
rgbValue = 15; 
rc = SQLSetConnectAttr(hdbc,SQL_LOGIN_TIMEOUT,&rgbValue,sizeof(rgbValue)); 
if(!FindError(SQL_HANDLE_DBC,szHYC00)) 
RETCHECK(SQL_SUCCESS,rc,szSQLSETCONNECTATTR); 
else 
RETCHECK(SQL_ERROR,rc,szSQLSETCONNECTATTR); 
} 
 
if((!fSupportSetConnectAttr) && fSupportGetConnectAttr) 
{ 
//test SQL_ACCESS_MODE 
rc = SQLGetConnectAttr(hdbc,SQL_ACCESS_MODE,&pvParam,sizeof(pvParam),NULL); 
if(!FindError(SQL_HANDLE_DBC,szHYC00)) 
RETCHECK(SQL_SUCCESS,rc,szSQLGETCONNECTATTR); 
else 
RETCHECK(SQL_ERROR,rc,szSQLGETCONNECTATTR); 
//test SQL_AUTOCOMMIT 
rc = SQLGetConnectAttr(hdbc,SQL_AUTOCOMMIT,&pvParam,sizeof(pvParam),NULL); 
if(!FindError(SQL_HANDLE_DBC,szHYC00)) 
RETCHECK(SQL_SUCCESS,rc,szSQLGETCONNECTATTR); 
else 
RETCHECK(SQL_ERROR,rc,szSQLGETCONNECTATTR); 
//test SQL_LOGIN_TIMEOUT 
rc = SQLGetConnectAttr(hdbc,SQL_LOGIN_TIMEOUT,&pvParam,sizeof(pvParam),NULL); 
if(!FindError(SQL_HANDLE_DBC,szHYC00)) 
RETCHECK(SQL_SUCCESS,rc,szSQLGETCONNECTATTR); 
else 
RETCHECK(SQL_ERROR,rc,szSQLGETCONNECTATTR); 
//SQL_ATTR_AUTO_IPD is a read-only attribute 
rc = SQLGetConnectAttr(hdbc,SQL_ATTR_AUTO_IPD,&pvParam,sizeof(pvParam),NULL); 
if(!FindError(SQL_HANDLE_DBC,szHYC00)) 
RETCHECK(SQL_SUCCESS,rc,szSQLGETCONNECTATTR); 
else 
RETCHECK(SQL_ERROR,rc,szSQLGETCONNECTATTR); 
} 
 
if(fSupportSetConnectAttr && fSupportGetConnectAttr) 
{ 
 
//test SQL_ACCESS_MODE 
TestConnectAttr(hdbc,SQL_ACCESS_MODE,SQL_MODE_READ_WRITE,TEXT("SQL_ACCESS_MODE"),FALSE); 
 
//test SQL_AUTOCOMMIT 
TestConnectAttr(hdbc,SQL_AUTOCOMMIT,SQL_AUTOCOMMIT_ON,TEXT("SQL_AUTOCOMMIT"),FALSE); 
 
//test SQL_LOGIN_TIMEOUT 
//the choice of 15 seconds for timeout is arbitrary 
TestConnectAttr(hdbc,SQL_LOGIN_TIMEOUT,15,TEXT("SQL_LOGIN_TIMEOUT"),FALSE); 
 
//SQL_ATTR_AUTO_IPD is a read-only attribute 
TestConnectAttr(hdbc,SQL_ATTR_AUTO_IPD,15,TEXT("SQL_ATTR_AUTO_IPD"),TRUE); 
} 
 
} //TestSQLSetConnectAttr() 
 
 
 
//----------------------------------------------------------------------------- 
//Function:  TestSQLSetStmtAttr 
//     This function tests both SQLSetStmtAttr and SQLGetStmtAttr 
//----------------------------------------------------------------------------- 
 
void  PASCAL TestSQLSetStmtAttr() 
{ 
RETCODE rc = SQL_SUCCESS, rc2= SQL_SUCCESS; 
UDWORDpvParam; 
UWORDrgbValue; 
BOOLfSupportSetStmtAttr = TRUE; 
BOOLfSupportGetStmtAttr = TRUE; 
 
//make sure these APIs are supported before testing 
if(!Supported(SQL_API_SQLSETSTMTATTR)) 
{ 
//the choice of 300 for SQL_MAX_LENGTH is arbitrary 
rgbValue = 300; 
fSupportSetStmtAttr = FALSE; 
rc = SQLSetStmtAttr(hstmt,SQL_MAX_LENGTH,&rgbValue,sizeof(rgbValue)); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(szSQLSETSTMTATTR,TEXT("did not return Not supported message")); 
RETCHECK(SQL_ERROR,rc,szSQLSETSTMTATTR); 
} 
 
if(!Supported(SQL_API_SQLGETSTMTATTR)) 
{ 
fSupportGetStmtAttr = FALSE; 
rc = SQLGetStmtAttr(hstmt,SQL_MAX_LENGTH,&pvParam,sizeof(pvParam),NULL); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(szSQLGETSTMTATTR,TEXT("did not return Not supported message")); 
RETCHECK(SQL_ERROR,rc,szSQLGETSTMTATTR); 
} 
 
if(fSupportSetStmtAttr && (!fSupportGetStmtAttr)) 
{ 
//test SQL_MAX_LENGTH 
rgbValue = 300; 
rc = SQLSetStmtAttr(hstmt,SQL_MAX_LENGTH,&rgbValue,sizeof(rgbValue)); 
if(!FindError(SQL_HANDLE_STMT,szHYC00)) 
RETCHECK(SQL_SUCCESS,rc,szSQLSETSTMTATTR); 
else 
RETCHECK(SQL_ERROR,rc,szSQLSETSTMTATTR); 
//test SQL_ATTR_METADATA_ID -- new in 3.0 
rgbValue = SQL_FALSE; 
rc = SQLSetStmtAttr(hstmt,SQL_ATTR_METADATA_ID,&rgbValue,sizeof(rgbValue)); 
if(!FindError(SQL_HANDLE_STMT,szHYC00)) 
RETCHECK(SQL_SUCCESS,rc,szSQLSETSTMTATTR); 
else 
RETCHECK(SQL_ERROR,rc,szSQLSETSTMTATTR); 
} 
 
if((!fSupportSetStmtAttr) && fSupportGetStmtAttr) 
{ 
//test SQL_MAX_LENGTH 
rc = SQLGetStmtAttr(hstmt,SQL_MAX_LENGTH,&pvParam,sizeof(pvParam),NULL); 
if(!FindError(SQL_HANDLE_STMT,szHYC00)) 
RETCHECK(SQL_SUCCESS,rc,szSQLGETSTMTATTR); 
else 
RETCHECK(SQL_ERROR,rc,szSQLGETSTMTATTR); 
//test SQL_ATTR_METADATA_ID -- new in 3.0 
rc = SQLGetStmtAttr(hstmt,SQL_ATTR_METADATA_ID,&pvParam,sizeof(pvParam),NULL); 
if(!FindError(SQL_HANDLE_STMT,szHYC00)) 
RETCHECK(SQL_SUCCESS,rc,szSQLGETSTMTATTR); 
else 
RETCHECK(SQL_ERROR,rc,szSQLGETSTMTATTR); 
} 
 
if(fSupportSetStmtAttr && fSupportGetStmtAttr) 
{ 
 
//test SQL_MAX_LENGTH 
rgbValue = 300; 
rc = SQLSetStmtAttr(hstmt,SQL_MAX_LENGTH,(PTR)rgbValue,sizeof(rgbValue)); 
if(!FindError(SQL_HANDLE_STMT,szHYC00)) 
{ 
RETCHECK(SQL_SUCCESS,rc,szSQLSETSTMTATTR); 
rc = SQLGetStmtAttr(hstmt,SQL_MAX_LENGTH,&pvParam,sizeof(pvParam),NULL); 
if(!FindError(SQL_HANDLE_STMT,szHYC00)) 
{ 
RETCHECK(SQL_SUCCESS,rc,szSQLGETSTMTATTR); 
if(pvParam != 300) 
DISPLAYERROR(szSQLGETSTMTATTR,TEXT("SQL_MAX_LENGTH returned incorrect value")); 
} 
else 
RETCHECK(SQL_ERROR,rc,szSQLGETSTMTATTR); 
} 
else 
RETCHECK(SQL_ERROR,rc,szSQLSETSTMTATTR); 
 
 
//test SQL_ATTR_METADATA_ID -- new in 3.0 
rgbValue = SQL_FALSE; 
rc = SQLSetStmtAttr(hstmt,SQL_ATTR_METADATA_ID,(PTR)rgbValue,sizeof(rgbValue)); 
if (!FindError(SQL_HANDLE_STMT,szHYC00) && !FindError(SQL_HANDLE_STMT,szHY092)) 
RETCHECK(SQL_SUCCESS,rc,szSQLSETSTMTATTR); 
 
rc2 = SQLGetStmtAttr(hstmt,SQL_ATTR_METADATA_ID,&pvParam,sizeof(pvParam),NULL); 
if (!FindError(SQL_HANDLE_STMT,szHYC00) && !FindError(SQL_HANDLE_STMT,szHY092)) 
RETCHECK(SQL_SUCCESS,rc,szSQLGETSTMTATTR); 
 
if (RC_SUCCESSFUL(rc) && RC_SUCCESSFUL(rc2) && pvParam != SQL_FALSE) 
DISPLAYERROR(szSQLGETSTMTATTR,TEXT("SQL_ATTR_METADATA_ID returned incorrect value")); 
} 
 
} //TestSQLSetStmtAttr() 
 
//-------------------------------------------------------------------------------- 
// FUNCTION:TestOneThread 
// PURPOSE:This function allocates the statement handle, performs simple  
//queries and deallocates the statement handle.  This function is called 
//by testthreading. 
//-------------------------------------------------------------------------------- 
static int TestOneThread(THREAD_STRUCT *ptArg) 
{ 
HENVhenv0 = ptArg->henv; 
HDBChdbc0 = ptArg->hdbc; 
HSTMThstmt0 = NULL; 
//RETCODErc=SQL_SUCCESS; 
 
/* allocate new statment handle */ 
if (RC_NOTSUCCESSFUL(SQLAllocHandle(SQL_HANDLE_STMT,hdbc0, &hstmt0))) 
return(FALSE); 
 
/* perform some simple catalog functions */ 
if (RC_NOTSUCCESSFUL(SQLStatistics(hstmt0,NULL,SQL_NTS,NULL,SQL_NTS,NULL,SQL_NTS,SQL_INDEX_ALL,SQL_QUICK))) 
return(FALSE); 
 
if (RC_NOTSUCCESSFUL(SQLCloseCursor(hstmt0))) 
return(FALSE); 
 
/* Get some data */ 
GetSomeData(hstmt0, ptArg->szTableName, TRUE,ptArg->rgFieldInfo); 
 
if (RC_NOTSUCCESSFUL(SQLGetTypeInfo(hstmt0,SQL_CHAR))) 
return(FALSE); 
 
// Cleanup 
if (RC_NOTSUCCESSFUL(SQLFreeHandle(SQL_HANDLE_STMT,hstmt0))) 
return(FALSE); 
 
return(TRUE); 
 
} //end of TestOneThread 
 
//-------------------------------------------------------------------------------- 
// FUNCTION:ThreadLoop 
// PURPOSE:This is the main loop for the threads, and it's called by  
//CreateThread() API. 
//-------------------------------------------------------------------------------- 
DWORD WINAPI ThreadLoop(void *pArg) 
{ 
 
THREAD_STRUCT *ptArg = (THREAD_STRUCT *)pArg; 
int i; 
RETCODErc; 
 
for(i=0; i< NUM_THREAD; i++) 
TestOneThread(ptArg); 
 
// free connection handle for each thread 
rc=SQLDisconnect(ptArg->hdbc); 
    RETCHECK(SQL_SUCCESS,rc,szSQLDISCONNECT); 
rc=SQLFreeHandle(SQL_HANDLE_DBC,ptArg->hdbc); 
RETCHECK(SQL_SUCCESS,rc,szSQLFREEHANDLE); 
 
   return(0); 
} //end of ThreadLoop 
 
 
//------------------------------------------------------------------------------- 
// FUNCTION:TestThreading 
// PURPOSE:This function tests the multi-threading capabilities of the  
//driver by creating multiple threads that connect to the same data 
// source.  Once connected, each thread performs simple queries to  
//test that the driver handles these queries successfully. 
//This function is to be called inside AutoTestFunc() in QuikTest. 
//-------------------------------------------------------------------------------- 
void TestThreading(lpSERVERINFO lpSI,QTSTRUCT  *lpqt,FIELDINFO *rgFieldInfo) 
{ 
RETCODE rc=SQL_SUCCESS; 
   THREAD_STRUCT *pArg; 
   HANDLE hThread[NUM_THREAD]; 
DWORD dwThreadId; 
UWORD i; 
HENVhenv1; 
HDBChdbc1; 
 
 
// allocate memory for the threads 
pArg = (THREAD_STRUCT *)AllocateMemory((NUM_THREAD) * sizeof(THREAD_STRUCT)); 
 
if(!pArg) 
{ 
szWrite(TEXT("\t\t\tMultiThreading Test interrupted due to error in memory allocation"), TRUE); 
return; 
} 
 
// only one environment handle will be needed for all threads 
rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv1); 
RETCHECK(SQL_SUCCESS, rc,szSQLALLOCHANDLE); 
 
// Set environment attribute, or we can't allocate connection 
rc = SQLSetEnvAttr(henv1, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 
SQL_IS_UINTEGER); 
RETCHECK(SQL_SUCCESS, rc,szSQLSETENVATTR); 
 
for (i=0; i < NUM_THREAD; i++ )  
{ 
// allocate connection handle for each thread 
rc=SQLAllocHandle(SQL_HANDLE_DBC,henv1, &hdbc1); 
RETCHECK(SQL_SUCCESS, rc,szSQLALLOCHANDLE); 
 
// create string to be used in connecting 
wsprintf(lpqt->sz,TEXT("dsn=%s;uid=%s;pwd=%s;"), 
lpSI->szValidServer0, 
lpSI->szValidLogin0, 
lpSI->szValidPassword0); 
 
SQLDriverConnect(hdbc1, lpSI->hwnd, lpqt->sz, 
SQL_NTS, lpqt->buf, MAX_STRING_SIZE, NULL, SQL_DRIVER_COMPLETE); 
 
// initialize thread structure 
pArg[i].henv = henv1; 
pArg[i].hdbc = hdbc1; 
lstrcpy(pArg[i].szTableName, lpqt->szTableName); 
pArg[i].rgFieldInfo=rgFieldInfo[0]; 
 
// start thread 
hThread[i]= CreateThread(NULL, 
0, 
ThreadLoop, 
&pArg[i], 
0, 
&dwThreadId); 
 
if(hThread[i]==0) 
{ 
DISPLAYERROR(TEXT("TestThread failed:"),TEXT("cannot create thread")); 
break; 
} 
} 
 
// wait for thread completion 
WaitForMultipleObjects(NUM_THREAD,hThread,TRUE,INFINITE); 
 
for(i=0; i<NUM_THREAD; i++ ) 
    CloseHandle(hThread[i]); 
 
SQLFreeHandle(SQL_HANDLE_ENV,henv1); 
if (pArg) 
ReleaseMemory(pArg); 
}//end of TestThreading() 
 
 
//----------------------------------------------------------------------- 
//      Function:               CreateDescRecord 
//----------------------------------------------------------------------- 
SWORD CreateDescRecord(SQLHDESC hdesc, SQLHSTMT hstmt, UWORD uwDescType) 
{ 
UDWORD cbColDef; 
SWORD swColCount; 
SQLRETURN rc; 
SWORD fType, fSQLType; 
SWORD ibScale; 
TCHAR rgBuf[100]; 
 
switch(uwDescType) { 
case SQL_ATTR_APP_ROW_DESC: 
rc = SQLSetDescField(hdesc, 1, SQL_DESC_TYPE, (SQLPOINTER)SQL_C_DEFAULT, 
SQL_IS_SMALLINT); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD); 
 
if (SQL_SUCCEEDED(rc)) 
return 1; 
 
rc=SQLBindCol(hstmt, 1, SQL_C_TCHAR, rgBuf, sizeof(rgBuf), NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLBINDCOL); 
if (SQL_SUCCEEDED(rc)) 
return 1; 
break; 
case SQL_ATTR_IMP_PARAM_DESC: 
case SQL_ATTR_APP_PARAM_DESC: 
// Select statement has already been done by this time 
rc=SQLDescribeCol(hstmt, 1, NULL, 0, NULL, &fSQLType, &cbColDef,  
&ibScale, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBECOL); 
if (!SQL_SUCCEEDED(rc)) 
return 0; 
 
if (SQL_ATTR_APP_PARAM_DESC == uwDescType) 
fType=SQL_C_TCHAR; 
else 
fType=fSQLType; 
 
rc = SQLSetDescField(hdesc, 1, SQL_DESC_TYPE, (SQLPOINTER)fType, 
SQL_IS_SMALLINT); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD); 
 
if (SQL_SUCCEEDED(rc)) 
return 1; 
 
rc=SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_TCHAR, 
fSQLType, cbColDef, ibScale, rgBuf, sizeof(rgBuf), NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBECOL); 
if (SQL_SUCCEEDED(rc)) 
return 1; 
break; 
case SQL_ATTR_IMP_ROW_DESC: 
// Quiktest has already done the select for us 
// Need to find out how many cols in result set 
rc=SQLNumResultCols(hstmt, &swColCount); 
if (SQL_SUCCEEDED(rc)) 
return(swColCount); 
break; 
} 
return 0; 
}//CreateDescRecord 
 
//----------------------------------------------------------------------- 
//      Function:               CheckDescOp 
//----------------------------------------------------------------------- 
void CheckDescOp(SQLHDESC hdesc, SQLRETURN rc, SQLUSMALLINT uwDescIndex, 
SQLSMALLINT swDescRecCount, SQLSMALLINT swDescRec, SQLUSMALLINT iDescField, 
SQLINTEGER swUpdateMode) 
{ 
TCHAR * pszAPI, szOp[10]; 
SQLSMALLINT fValidOp;// Descriptor types operation is valid for 
 
if (DESC_UPDATE_MODE_READ == swUpdateMode) 
{ 
pszAPI=szSQLGETDESCFIELD; 
lstrcpy(szOp, TEXT("read")); 
fValidOp=rgDescInfo[iDescField].fGettable; 
} 
else 
{ 
pszAPI=szSQLSETDESCFIELD; 
lstrcpy(szOp, TEXT("write")); 
fValidOp=rgDescInfo[iDescField].fSettable; 
} 
 
// If we're reading beyond the last record, expect SQL_NO_DATA. 
if (swDescRec > swDescRecCount && DESC_UPDATE_MODE_READ == swUpdateMode) 
{ 
wsprintf(buf,TEXT("%s: Able to %s descriptor field %s in the %s beyond last record."), 
pszAPI, szOp, rgDescInfo[iDescField].szDescFieldName, DescTypes[uwDescIndex].szDescName); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_NO_DATA, rc, buf); 
} 
else 
{ 
if (fValidOp & DescTypes[uwDescIndex].uwTypeMask) 
{ 
wsprintf(buf,TEXT("%s: Unable to %s descriptor field %s in the %s"), 
pszAPI, szOp, rgDescInfo[iDescField].szDescFieldName, DescTypes[uwDescIndex].szDescName); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, buf); 
} 
else 
{ 
wsprintf(buf,TEXT("%s: Able to %s descriptor field %s in the %s"), 
pszAPI, szOp, rgDescInfo[iDescField].szDescFieldName, DescTypes[uwDescIndex].szDescName); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_ERROR, rc, buf); 
} 
} 
} 
 
//----------------------------------------------------------------------- 
// 
// Function: CompareDescField 
// 
// Compares two fields from the given descriptor, or to rgDescInfo if hdesc2 
// is NULL.  uwDescField contains the entry in rgDescInfo for the desired field  
//----------------------------------------------------------------------- 
 
void CompareDescField(SQLHDESC hdesc1, SQLHDESC hdesc2, SQLUSMALLINT uwDescIndex, 
SQLSMALLINT swDescRec, SQLSMALLINT swDescRecCount, SQLUSMALLINT uwDescField, 
TCHAR * pszAPI) 
{ 
SQLRETURN rc; 
 SQLTCHAR DescBuf2[MAX_DESC_BUF]; 
SQLINTEGER cbValue2;  
 
// Make sure we've got a valid descriptor handle for hdesc1 
// (hdesc2 is allowed to be NULL) 
if (SQL_NULL_HDESC == hdesc1) { 
wsprintf(buf,TEXT("\t\tCompareDescriptor: hdesc1 handle was null!")); 
DISPLAYERROR(pszAPI, buf); 
return; 
} 
 
// Read the value from hdesc1 
rc = SQLGetDescField(hdesc1, swDescRec, rgDescInfo[uwDescField].uwDescField, 
&DescBuf, sizeof(DescBuf), &cbValue); 
 
CheckDescOp(hdesc1, rc, uwDescIndex, swDescRecCount, swDescRec, uwDescField, DESC_UPDATE_MODE_READ); 
 
cbValue2=rgDescInfo[uwDescField].cbValue; 
 
// Get the value to compare to 
if (SQL_NULL_HDESC == hdesc2) { 
 
// Compare to rgDescInfo if it's settable 
if (rgDescInfo[uwDescField].fSettable & DescTypes[uwDescIndex].uwTypeMask) { 
 
// Copy the set value into DescBuf2.  For char fields size is 0 
// (unknown), and the new value is actually the pointer to the start 
// of the string. 
SQLPOINTER pNewvalue = &(rgDescInfo[uwDescField].NewValue); 
 
if (!rgDescInfo[uwDescField].size) 
{ 
pNewvalue = (SQLPOINTER)rgDescInfo[uwDescField].NewValue; 
cbValue2= (lstrlen(pNewvalue)+1) * sizeof(TCHAR);  
} 
 
memcpy(&DescBuf2, pNewvalue, cbValue2); 
} 
} 
else { 
 
// Compare to hdesc2 
rc = SQLGetDescField(hdesc2, swDescRec, rgDescInfo[uwDescField].uwDescField, 
&DescBuf2, sizeof(DescBuf2), &cbValue); 
 
// Since hdesc2 is an unassociated hdesc, treat it as an ARD 
// (uwDescIndex=0) 
CheckDescOp(hdesc2, rc, 0, swDescRecCount, swDescRec, uwDescField, DESC_UPDATE_MODE_READ); 
} 
 
// Perform the compare if settable in source desc and settable in 
// target desc (application descriptors) when using hdesc2 
if (rgDescInfo[uwDescField].fSettable & DescTypes[uwDescIndex].uwTypeMask) 
{ 
if (!hdesc2 || (rgDescInfo[uwDescField].fSettable & DESC_ARD)) 
{ 
// IPD field SQL_DESC_TYPE is settable for consitency check, but set 
// value can't be retrieved, so skip compare in this case 
if (SQL_ATTR_IMP_PARAM_DESC != DescTypes[uwDescIndex].uwDescType || 
SQL_DESC_DATA_PTR != rgDescInfo[uwDescField].uwDescField) 
{ 
if (memcmp(DescBuf, DescBuf2, cbValue2)) { 
// Compare error, print message 
wsprintf(buf,TEXT("Compare error in %s field %s"), 
DescTypes[uwDescIndex].szDescName,rgDescInfo[uwDescField].szDescFieldName); 
DISPLAYERROR(pszAPI, buf); 
} 
} 
} 
} 
} 
 
 
//----------------------------------------------------------------------- 
// 
// Function:  CheckDescriptor 
// 
// Checks all fields in all records of given descriptor.  If swUpdateMode is 
// DESC_UPDATE_MODE_READ then all fields are read, otherwise all updatable 
// fields are written. 
//----------------------------------------------------------------------- 
void CheckDescriptor(SQLHDESC hdesc, SQLINTEGER swUpdateMode, SQLHSTMT hstmt, UWORD uwDescIndex) 
{ 
 SQLINTEGER cbValue2; 
SQLSMALLINT swDescRec=0, swDescRecCount, swAdditionalRecs=0; 
SQLUSMALLINT iDescField, iStartField=0; 
SQLRETURN rc; 
 
// Get the descriptor record count. 
rc = SQLGetDescField(hdesc, 0, SQL_DESC_COUNT, &swDescRecCount, 
sizeof(swDescRecCount), &cbValue); 
 
if (SQL_SUCCESS == rc) { 
 
// In read mode, try to read one past last record 
if (swUpdateMode == DESC_UPDATE_MODE_READ) 
swAdditionalRecs=1; 
 
// Check all records, including header 
for (swDescRec=0; swDescRec <= swDescRecCount+swAdditionalRecs; swDescRec++) { 
 
// Check all fields 
for (iDescField=iStartField; iDescField < sizeof(rgDescInfo)/sizeof(rgDescInfo[0]); iDescField++) { 
 
// If we've gone past the header fields, then break out of loop to check record fields 
if (0 == swDescRec && !rgDescInfo[iDescField].fHeader) { 
iStartField=iDescField; 
break; 
} 
 
if (DESC_UPDATE_MODE_READ == swUpdateMode) 
{ 
// Read from the field 
rc = SQLGetDescField(hdesc, swDescRec, rgDescInfo[iDescField].uwDescField, 
&DescBuf, sizeof(DescBuf), &cbValue); 
 
CheckDescOp(hdesc, rc, uwDescIndex, swDescRecCount, swDescRec, iDescField, swUpdateMode); 
 
if (RC_SUCCESSFUL(rc)) 
{ 
// Compare cbValue with expected 
cbValue2=rgDescInfo[iDescField].cbValue; // For most fields 
 
if (!rgDescInfo[iDescField].size) 
cbValue2 = lstrlen((LPTSTR)DescBuf);  // For string fields 
 
// Make sure cbValue and cbValue2 agree 
if (cbValue != cbValue2) 
{ 
wsprintf(buf,TEXT("Compare error in %s field %s, expected")\ 
TEXT(" StringLength %d, received %d"), DescTypes[uwDescIndex].szDescName, 
rgDescInfo[iDescField].szDescFieldName, cbValue2, cbValue); 
DISPLAYERROR(szSQLGETDESCFIELD, buf); 
} 
} 
} 
else 
{ 
// Write to the field.  For char fields size is 0 (unknown), 
// so compute the length of the string 
rc = SQLSetDescField(hdesc, swDescRec, rgDescInfo[iDescField].uwDescField, 
(SQLPOINTER)rgDescInfo[iDescField].NewValue, 
(rgDescInfo[iDescField].size) ? rgDescInfo[iDescField].size : 
lstrlen((LPTSTR)rgDescInfo[iDescField].NewValue)*sizeof(TCHAR)); 
 
CheckDescOp(hdesc, rc, uwDescIndex, swDescRecCount, swDescRec, iDescField, swUpdateMode); 
 
if (RC_SUCCESSFUL(rc)) 
CompareDescField(hdesc, NULL, uwDescIndex, swDescRec, swDescRecCount,iDescField, szSQLSETDESCFIELD); 
} 
} 
} 
} 
else { 
// Unable to read record count from descriptor header, can't proceed 
wsprintf(buf,TEXT("\t\tUnable to read record count from descriptor header.")); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, buf); 
} 
} 
 
//----------------------------------------------------------------------- 
// 
// Function:  CompareDescriptor 
// 
// Compares two descriptors, or if hdesc2 is NULL compares hdesc1 to rgDescInfo 
// updatable columns 
//----------------------------------------------------------------------- 
 
void CompareDescriptor(SQLHDESC hdesc1, SQLHDESC hdesc2, UWORD uwDescIndex, TCHAR * pszAPI) 
{ 
 SQLSMALLINT swDescRec, swDescRecCount; 
SQLUSMALLINT iDescField, iStartField=0; 
SQLRETURN rc; 
 
// Make sure we've got a valid descriptor handle for hdesc1 
// (hdesc2 is allowed to be NULL) 
if (SQL_NULL_HDESC == hdesc1) { 
wsprintf(buf,TEXT("\t\thCompareDescriptor: hdesc1 handle was null!")); 
DISPLAYERROR(szSQLGETDESCFIELD, buf); 
return; 
} 
 
// Get the descriptor record count. 
rc = SQLGetDescField(hdesc1, 0, SQL_DESC_COUNT, &swDescRecCount, 
sizeof(swDescRecCount), &cbValue); 
 
if (SQL_SUCCESS == rc) { 
 
// Check all records, including header 
for (swDescRec=0; swDescRec <= swDescRecCount; swDescRec++) { 
 
// Check all fields 
for (iDescField=iStartField; iDescField < sizeof(rgDescInfo)/sizeof(rgDescInfo[0]); iDescField++) { 
 
// If we've gone past the header fields, then break out of loop to check record fields 
if (0 == swDescRec && !rgDescInfo[iDescField].fHeader) { 
iStartField=iDescField; 
break; 
} 
 
CompareDescField(hdesc1, hdesc2, uwDescIndex, swDescRec, swDescRecCount, iDescField, pszAPI); 
} 
} 
} 
else { 
// Unable to read record count from descriptor header, can't proceed 
wsprintf(buf,TEXT("\t\tUnable to read record count from descriptor header.")); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_SUCCESS, rc, buf); 
} 
} 
 
 
void CheckDescRecord(SQLHDESC hdesc, SQLSMALLINT swDescRec, SQLSMALLINT fType, 
           SQLSMALLINT fSubType, SQLINTEGER cbLength, SQLSMALLINT ibPrecision, SQLSMALLINT ibScale, 
           SQLPOINTER pData, SQLINTEGER *pcbValue, SQLINTEGER *pIndicator, SQLUSMALLINT iDescType) 
{ 
SQLINTEGER Length, * pIndicator2; 
PTR pDescPtr; 
SQLRETURN rc; 
SQLSMALLINT fType2, fSubType2, cbName, Precision, Scale, Nullable; 
TCHARszName[MAX_DESC_BUF]=TEXT(""); 
 
// Write the record 
rc = SQLSetDescRec(hdesc, swDescRec, fType, fSubType, cbLength, ibPrecision,  
ibScale, pData, pcbValue, pIndicator); 
 
// Can't set IRD, so it should error 
if (SQL_ATTR_IMP_ROW_DESC == DescTypes[iDescType].uwDescType) 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_ERROR, rc, szSQLSETDESCREC); 
else 
{ 
wsprintf(buf,TEXT("%s: Unable to write record %d in %s"), 
szSQLSETDESCREC, swDescRec, DescTypes[iDescType].szDescName); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, buf); 
} 
 
if (RC_SUCCESSFUL(rc)) 
{ 
// Read it again 
rc = SQLGetDescRec(hdesc, swDescRec, szName, sizeof(szName), &cbName, &fType2, 
&fSubType2, &Length, &Precision, &Scale, &Nullable); 
 
wsprintf(buf,TEXT("%s: Unable to read record %d in %s"), 
szSQLGETDESCREC, swDescRec, DescTypes[iDescType].szDescName); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, buf); 
 
if (RC_SUCCESSFUL(rc)) 
{ 
// Compare values 
if (fType2 != fType) 
DISPLAYERROR(szSQLSETDESCREC,TEXT("fType not set correctly")); 
 
if (Precision != ibPrecision) 
DISPLAYERROR(szSQLSETDESCREC,TEXT("ibPrecision not set correctly")); 
 
switch(fType) 
{ 
case SQL_DECIMAL: 
case SQL_NUMERIC: 
case SQL_C_DOUBLE: 
case SQL_C_FLOAT: 
// Scale is only defined for NUMERIC or DECIMAL types 
if (Scale != ibScale) 
DISPLAYERROR(szSQLSETDESCREC,TEXT("ibScale not set correctly")); 
break; 
case SQL_DATETIME: 
case SQL_INTEGER: 
// Subtype is only valid for DATETIME or INTERVAL types 
if (fSubType2 != fSubType) 
DISPLAYERROR(szSQLSETDESCREC,TEXT("fSubType not set correctly")); 
break; 
} 
 
// For application descriptors, compare the Length and get the 
// data ptr value to check for accuracy 
switch(DescTypes[iDescType].uwDescType) 
{ 
case SQL_ATTR_APP_ROW_DESC: 
case SQL_ATTR_APP_PARAM_DESC: 
 
if (Length != cbLength) 
DISPLAYERROR(szSQLSETDESCREC,TEXT("cbLength not set correctly")); 
 
rc = SQLGetDescField(hdesc, swDescRec, SQL_DESC_DATA_PTR, 
&pDescPtr, sizeof(PTR), &cbValue); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, szSQLGETDESCFIELD); 
 
if (pDescPtr != pData) 
DISPLAYERROR(szSQLSETDESCREC,TEXT("rgbValue not set correctly")); 
 
// Get the octet length ptr value and check for accuracy 
rc = SQLGetDescField(hdesc, swDescRec, SQL_DESC_OCTET_LENGTH_PTR, 
&pDescPtr, sizeof(PTR), &cbValue); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, szSQLGETDESCFIELD); 
 
if (pDescPtr != pcbValue) 
DISPLAYERROR(szSQLSETDESCREC,TEXT("cbValue not set correctly")); 
 
rc = SQLGetDescField(hdesc, swDescRec, SQL_DESC_INDICATOR_PTR, 
&pIndicator2, sizeof(PTR), &cbValue); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, szSQLGETDESCFIELD); 
 
if (pIndicator2 != pIndicator) 
DISPLAYERROR(szSQLSETDESCREC,TEXT("Indicator not set correctly")); 
 
break; 
case SQL_ATTR_IMP_ROW_DESC: 
case SQL_ATTR_IMP_PARAM_DESC: 
break; 
default: 
DISPLAYERROR(szSQLSETDESCREC,TEXT("Unknown descriptor type.")); 
} 
} 
} 
 
} 
 
SQLRETURN DescBindParameter(SQLHSTMT hstmt, SQLUSMALLINT ipar, 
    SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType, 
    SQLUINTEGER cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, 
    SQLINTEGER cbValueMax, SQLINTEGER  *pcbValue) 
{ 
SQLHDESC hdescAPD, hdescIPD; 
SQLRETURN rc; 
 
rc = SQLGetStmtAttr(hstmt, SQL_ATTR_APP_PARAM_DESC, &hdescAPD, sizeof(hdescAPD), NULL);   
if (!RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR)) 
return rc; 
 
rc = SQLGetStmtAttr(hstmt, SQL_ATTR_IMP_PARAM_DESC, &hdescIPD, sizeof(hdescIPD), NULL);   
if (!RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR)) 
return rc; 
 
// Parameter type 
rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_PARAMETER_TYPE, (SQLPOINTER)fParamType, 
SQL_IS_SMALLINT);// Set ipar and fParamType for IPD 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
 
// C type 
rc = SQLSetDescField(hdescAPD, ipar, SQL_DESC_CONCISE_TYPE, (SQLPOINTER)fCType, 
SQL_IS_SMALLINT);// Set ipar and fCType of APD 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescAPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
 
// Sql type 
rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_CONCISE_TYPE, (SQLPOINTER)fSqlType, 
SQL_IS_SMALLINT);// Set fSqlType of IPD 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
 
// Column Size (Length or Precision) 
if (fSqlType == SQL_CHAR || 
fSqlType == SQL_VARCHAR || 
fSqlType == SQL_LONGVARCHAR || 
fSqlType == SQL_BINARY || 
fSqlType == SQL_VARBINARY || 
fSqlType == SQL_LONGVARBINARY || 
fSqlType == SQL_TYPE_DATE || 
fSqlType == SQL_TYPE_TIME || 
fSqlType == SQL_TYPE_TIMESTAMP || 
(fSqlType >= SQL_INTERVAL_YEAR && 
 fSqlType <= SQL_INTERVAL_MINUTE_TO_SECOND)) 
{ 
rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_LENGTH, (SQLPOINTER)cbColDef, 
SQL_IS_UINTEGER);// Set cbColDef (Length) of IPD 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
} 
else if (fSqlType == SQL_DECIMAL || 
fSqlType == SQL_NUMERIC || 
 fSqlType == SQL_FLOAT || 
 fSqlType == SQL_REAL || 
 fSqlType == SQL_DOUBLE) 
{ 
rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_PRECISION, (SQLPOINTER)cbColDef, 
SQL_IS_SMALLINT);// Set cbColDef (Precision) of IPD 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
} 
 
// Scale 
if (fSqlType == SQL_TYPE_DATE || 
fSqlType == SQL_TYPE_TIME || 
fSqlType == SQL_TYPE_TIMESTAMP || 
(fSqlType >= SQL_INTERVAL_YEAR && 
 fSqlType <= SQL_INTERVAL_MINUTE_TO_SECOND)) 
{ 
switch(fSqlType) 
{ 
case SQL_TYPE_TIME: 
case SQL_TYPE_TIMESTAMP: 
case SQL_INTERVAL_SECOND: 
case SQL_INTERVAL_DAY_TO_SECOND: 
case SQL_INTERVAL_HOUR_TO_SECOND: 
case SQL_INTERVAL_MINUTE_TO_SECOND: 
rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_PRECISION, (SQLPOINTER)ibScale, 
SQL_IS_SMALLINT);// Set scale of IPD 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
break; 
default: 
rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_PRECISION, (SQLPOINTER)0, 
SQL_IS_SMALLINT);// Set scale of IPD 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
} 
} 
else 
{ 
rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_SCALE, (SQLPOINTER)ibScale, 
SQL_IS_SMALLINT);// Set scale of IPD 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
} 
 
// cbValueMax 
rc = SQLSetDescField(hdescAPD, ipar, SQL_DESC_OCTET_LENGTH, (SQLPOINTER)cbValueMax, 
SQL_IS_INTEGER);// Set cbValueMax of APD 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescAPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
 
// pcbValue 
rc = SQLSetDescField(hdescAPD, ipar, SQL_DESC_OCTET_LENGTH_PTR, (SQLPOINTER)pcbValue, 
SQL_IS_POINTER);// Set pcbValue/octet length 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescAPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
 
rc = SQLSetDescField(hdescAPD, ipar, SQL_DESC_INDICATOR_PTR, (SQLPOINTER)pcbValue, 
SQL_IS_POINTER);// Set pcbValue/indicator 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescAPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
 
// Data ptr 
rc = SQLSetDescField(hdescAPD, ipar, SQL_DESC_DATA_PTR, (SQLPOINTER)rgbValue, 
SQL_IS_POINTER);// Set rgbValue 
ERRSHANDLE(SQL_HANDLE_DESC, hdescAPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD); 
 
return rc; 
 
} 
 
SQLRETURN DescBindCol(SQLHSTMT hstmt, SQLSMALLINT icol, 
           SQLSMALLINT fCType, SQLPOINTER rgbValue, 
           SQLINTEGER cbValueMax, SQLINTEGER *pcbValue) 
{ 
SQLHDESC hdesc; 
SQLRETURN rc; 
 
rc = SQLGetStmtAttr(hstmt, SQL_ATTR_APP_ROW_DESC, &hdesc, sizeof(hdesc), NULL);   
if (!RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR)) 
return rc; 
 
rc = SQLSetDescField(hdesc, icol, SQL_DESC_CONCISE_TYPE, (SQLPOINTER)fCType, 
SQL_IS_SMALLINT);// Set icol and fCType 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
 
rc = SQLSetDescField(hdesc, icol, SQL_DESC_OCTET_LENGTH, (SQLPOINTER)cbValueMax, 
SQL_IS_INTEGER);// Set cbValueMax 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
 
rc = SQLSetDescField(hdesc, icol, SQL_DESC_OCTET_LENGTH_PTR, (SQLPOINTER)pcbValue, 
SQL_IS_POINTER);// Set pcbValue/octet length 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
 
rc = SQLSetDescField(hdesc, icol, SQL_DESC_INDICATOR_PTR, (SQLPOINTER)pcbValue, 
SQL_IS_POINTER);// Set pcbValue/indicator 
if (!ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD)) 
return rc; 
 
rc = SQLSetDescField(hdesc, icol, SQL_DESC_DATA_PTR, (SQLPOINTER)rgbValue, 
SQL_IS_POINTER);// Set rgbValue 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD); 
 
return rc; 
} 
 
//----------------------------------------------------------------------- 
//      Function:               TestGetDescField 
//----------------------------------------------------------------------- 
 
void  PASCAL TestGetDescField(QTSTRUCT * lpqt) 
{ 
SQLRETURN rc=SQL_SUCCESS; 
SQLUSMALLINT iDescType; 
 
SQLHDESC hdesc1=NULL, hdesc2=NULL; 
PTR rgbValue=NULL; 
SQLSMALLINT swDescRecCount, swExpRecCount; 
SQLINTEGER cbValue; 
TCHARszName[MAX_DESC_BUF]=TEXT(""); 
TCHARszQuery[XLARGEBUFF]=TEXT(""); 
 
if (!Supported(SQL_API_SQLGETDESCFIELD)) 
{ 
// Allocate a default descriptor 
rc = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc);   
 
if (RC_SUCCESSFUL(rc)) 
{ 
 rc = SQLGetDescField(hdesc, 0, SQL_DESC_COUNT, &DescBuf, sizeof(DescBuf), 
&cbValue); 
 
if(!FindError(SQL_HANDLE_DESC,szIM001)) 
DISPLAYERROR(szSQLGETDESCFIELD, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLGETDESCFIELD); 
} 
} 
else 
{ 
// Make sure all parameters and columns are unbound 
ResetHstmt(&hstmt); 
 
// Perform a select stmt 
wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName); 
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
// For each descriptor type 
for (iDescType=0; iDescType < sizeof(DescTypes)/sizeof(DescTypes[0]); iDescType++) 
{ 
 
// Get the handle for the automatically allocated descriptor 
rc = SQLGetStmtAttr(hstmt, DescTypes[iDescType].uwDescType, &hdesc1, sizeof(hdesc1), &cbValue);   
RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR); 
 
// Create a descriptor record so we have something to read besides header 
swExpRecCount=CreateDescRecord(hdesc1, hstmt, DescTypes[iDescType].uwDescType); 
 
// Get the count of descriptor records (iRecord ignored for header fields) 
rc = SQLGetDescField(hdesc1, 0, SQL_DESC_COUNT, &swDescRecCount, 
sizeof(swDescRecCount), &cbValue); 
 
if (SQL_SUCCEEDED(rc))  
{ 
// Check count value for expected 
if (swExpRecCount != swDescRecCount) 
{ 
wsprintf(buf,TEXT("Expected record count %d, found %d"), 
swExpRecCount, swDescRecCount); 
DISPLAYERROR(szSQLGETDESCFIELD, buf); 
} 
 
CheckDescriptor(hdesc1, DESC_UPDATE_MODE_READ, hstmt, iDescType); 
} 
else 
{ 
// Unable to read record count from descriptor header, can't proceed 
wsprintf(buf,TEXT("Unable to read record count from descriptor header for descriptor type %d"), 
DescTypes[iDescType].szDescName); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_SUCCESS, rc, buf); 
} 
} 
 
rc=SQLCloseCursor(hstmt); 
RETCHECK(SQL_SUCCESS, rc,szSQLCLOSECURSOR); 
} 
 
 
} // TestGetDescField() 
 
//----------------------------------------------------------------------- 
//      Function:               TestSetDescField 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSetDescField(QTSTRUCT * lpqt) 
{ 
SQLRETURN rc=SQL_SUCCESS; 
SQLUSMALLINT iDescType; 
 
SQLHDESC hdesc1=NULL, hdesc2=NULL; 
PTR rgbValue=NULL; 
SQLSMALLINT swDescRecCount, swExpRecCount; 
SQLINTEGER cbValue; 
TCHARszName[MAX_DESC_BUF]=TEXT(""); 
TCHARszQuery[XLARGEBUFF]=TEXT(""); 
 
 
if (!Supported(SQL_API_SQLSETDESCFIELD)) 
{ 
// Allocate a default descriptor 
rc = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc);   
 
if (RC_SUCCESSFUL(rc)) 
{ 
rc = SQLSetDescField(hdesc, 0, SQL_DESC_COUNT, &swDescRecCount, 
sizeof(swDescRecCount)); 
 
if(!FindError(SQL_HANDLE_DESC,szIM001)) 
DISPLAYERROR(szSQLSETDESCFIELD, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLSETDESCFIELD); 
} 
} 
else 
{ 
// Make sure all parameters and columns are unbound 
ResetHstmt(&hstmt); 
 
// Perform a select stmt 
wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName); 
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
// For each descriptor type 
for (iDescType=0; iDescType < sizeof(DescTypes)/sizeof(DescTypes[0]); iDescType++) 
{ 
 
// Get the handle for the automatically allocated descriptor 
rc = SQLGetStmtAttr(hstmt, DescTypes[iDescType].uwDescType, &hdesc1, sizeof(hdesc1), &cbValue);   
RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR); 
 
// Create a descriptor record so we have something to read besides header 
swExpRecCount=CreateDescRecord(hdesc1, hstmt, DescTypes[iDescType].uwDescType); 
 
// Update all descriptor records to new values 
CheckDescriptor(hdesc1, DESC_UPDATE_MODE_WRITE, hstmt, iDescType); 
 
// Compare the descriptor with the update values 
// CompareDescriptor(hdesc1, NULL, iDescType, szSQLSETDESCFIELD); 
} 
 
ResetHstmt(&hstmt); 
} 
 
} //TestSetDescField() 
 
//----------------------------------------------------------------------- 
//      Function:               TestGetDescRec 
//----------------------------------------------------------------------- 
 
void  PASCAL TestGetDescRec(QTSTRUCT * lpqt) 
{ 
SQLRETURN rc=SQL_SUCCESS; 
SQLUSMALLINT iDescType; 
 
SQLHDESC hdesc1=NULL, hdesc2=NULL; 
PTR rgbValue=NULL; 
SQLSMALLINT swDescRec, swDescRecCount, iRecord, cbNameMax, cbName, fType, fSubType, 
Precision, Scale, Nullable, swExpRecCount; 
SQLINTEGER Length, cbValue; 
TCHARszName[MAX_DESC_BUF]=TEXT(""); 
TCHARszQuery[XLARGEBUFF]=TEXT(""); 
 
 
if (!Supported(SQL_API_SQLGETDESCREC)) 
{ 
// Allocate a default descriptor 
rc = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc);   
 
if (RC_SUCCESSFUL(rc)) 
{ 
rc = SQLGetDescRec(hdesc, iRecord, szName, cbNameMax, &cbName, &fType, 
&fSubType, &Length, &Precision, &Scale, &Nullable); 
 
if(!FindError(SQL_HANDLE_DESC,szIM001)) 
DISPLAYERROR(szSQLGETDESCREC, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLGETDESCREC); 
} 
} 
else 
{ 
// Make sure all parameters and columns are unbound 
ResetHstmt(&hstmt); 
 
// Turn on bookmarks so we can retrieve from record 0 of ARD 
rc = SQLSetStmtAttr(hstmt, SQL_ATTR_USE_BOOKMARKS, (SQLPOINTER)SQL_UB_ON, SQL_IS_INTEGER); 
RETCHECK(SQL_SUCCESS, rc,szSQLSETSTMTATTR); 
 
// Perform a select stmt 
wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName); 
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
// For each descriptor type 
for (iDescType=0; iDescType < sizeof(DescTypes)/sizeof(DescTypes[0]); iDescType++) 
{ 
 
// Get the handle for the automatically allocated descriptor 
rc = SQLGetStmtAttr(hstmt, DescTypes[iDescType].uwDescType, &hdesc1, sizeof(hdesc1), &cbValue);   
RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR); 
 
// Create a descriptor record so we have something to read besides header 
swExpRecCount=CreateDescRecord(hdesc1, hstmt, DescTypes[iDescType].uwDescType); 
 
// Get the count of descriptor records 
// Count for automatically allocated descriptors is written in 
// SetDescField test. 
rc = SQLGetDescField(hdesc1, 0, SQL_DESC_COUNT, &swDescRecCount, 
sizeof(swDescRecCount), &cbValue); 
 
if (SQL_SUCCESS == rc)  
{ 
 
// For all descriptor records 
for (swDescRec=0; swDescRec <= swDescRecCount+1; swDescRec++) 
{ 
// Read the record 
rc = SQLGetDescRec(hdesc1, swDescRec, szName, sizeof(szName), &cbName, &fType, 
&fSubType, &Length, &Precision, &Scale, &Nullable); 
 
if (swDescRec <= swDescRecCount) 
{ 
// Retrieving bookmark on IPD is an error 
if (SQL_ATTR_IMP_PARAM_DESC == DescTypes[iDescType].uwDescType && 0 == swDescRec) 
{ 
wsprintf(buf,TEXT("%s: Able to read record %d from %s"), 
szSQLGETDESCREC, swDescRec, DescTypes[iDescType].szDescName); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_ERROR, rc, buf); 
} 
else 
{ 
wsprintf(buf,TEXT("%s: Unable to read record %d from %s"), 
szSQLGETDESCREC, swDescRec, DescTypes[iDescType].szDescName); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_SUCCESS, rc, buf); 
} 
} 
else 
{ 
wsprintf(buf,TEXT("%s: Did not receive SQL_NO_DATA reading record %d from %s"), 
szSQLGETDESCREC, swDescRec, DescTypes[iDescType].szDescName); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_NO_DATA, rc, buf); 
} 
} 
} 
else 
{ 
// Unable to read record count from descriptor header, can't proceed 
wsprintf(buf,TEXT("\t\tUnable to read record count from descriptor header for %s"), 
DescTypes[iDescType].szDescName); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_SUCCESS, rc, buf); 
} 
} 
 
rc=SQLCloseCursor(hstmt); 
RETCHECK(SQL_SUCCESS, rc,szSQLCLOSECURSOR); 
 
} 
 
} //TestGetDescRec() 
 
//----------------------------------------------------------------------- 
//      Function:               TestSetDescRec 
//----------------------------------------------------------------------- 
 
void  PASCAL TestSetDescRec(QTSTRUCT * lpqt) 
{ 
SQLRETURN rc=SQL_SUCCESS; 
SQLINTEGER cbLength, cbValue, Indicator; 
SQLUSMALLINT iDescType; 
 
SQLHDESC hdesc1=NULL, hdesc2=NULL; 
PTR rgbValue=NULL; 
SQLSMALLINT swDescRec, swDescRecCount, swStartRec=1, iRecord, fType, fSubType, 
ibPrecision, ibScale; 
SQLSMALLINT swExpRecCount; 
TCHARszQuery[XLARGEBUFF]=TEXT(""); 
 
 
if (!Supported(SQL_API_SQLSETDESCREC)) 
{ 
// Allocate a default descriptor 
rc = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc);   
 
if (RC_SUCCESSFUL(rc)) 
{ 
rc = SQLSetDescRec(hdesc, iRecord, fType, fSubType, cbLength, 
ibPrecision, ibScale, &DescBuf, &cbValue, &Indicator); 
 
if(!FindError(SQL_HANDLE_DESC,szIM001)) 
DISPLAYERROR(szSQLSETDESCREC, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLSETDESCREC); 
} 
} 
else 
{ 
// Make sure all parameters and columns are unbound 
ResetHstmt(&hstmt); 
 
// Perform a select stmt 
wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName); 
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
// If bookmarks are supported, then we want to try to set record 0 
rc = SQLSetStmtAttr(hstmt, SQL_ATTR_USE_BOOKMARKS, 
(PTR)SQL_UB_VARIABLE, SQL_IS_INTEGER); 
if (RC_SUCCESSFUL(rc)) 
swStartRec=0; 
 
// For each descriptor type 
for (iDescType=0; iDescType < sizeof(DescTypes)/sizeof(DescTypes[0]); iDescType++) 
{ 
 
// Get the handle for the automatically allocated descriptor 
rc = SQLGetStmtAttr(hstmt, DescTypes[iDescType].uwDescType, &hdesc1, sizeof(hdesc1), &cbValue);   
RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR); 
 
// Create a descriptor record so we have something to read besides header 
swExpRecCount=CreateDescRecord(hdesc1, hstmt, DescTypes[iDescType].uwDescType); 
 
// Get the count of descriptor records 
rc = SQLGetDescField(hdesc1, 0, SQL_DESC_COUNT, &swDescRecCount, 
sizeof(swDescRecCount), &cbValue); 
 
if (SQL_SUCCESS == rc)  
{ 
 
// For all descriptor records 
for (swDescRec=swStartRec; swDescRec <= swDescRecCount; swDescRec++) 
{ 
// Test with a DATETIME record so we can check the subtype field. 
SQLINTEGER Indicator=0; 
fType=SQL_DATETIME; 
fSubType=SQL_CODE_TIMESTAMP; 
cbLength=sizeof(TIMESTAMP_STRUCT); 
ibPrecision=5; // For DATETIME, SQL_CODE_DATE data 
// precision defaults to 0, but it implies it can be set otherwise. 
ibScale=0;// Only used for DECIMAL or NUMERIC types, otherwise undefined 
 
CheckDescRecord(hdesc1, swDescRec, fType, fSubType, cbLength, ibPrecision,  
ibScale, &tsval, &cbValue, &Indicator, iDescType); 
 
// Test with a numeric record to test scale 
Indicator=0; 
fType=SQL_NUMERIC; 
fSubType=SQL_CODE_TIMESTAMP; 
cbLength=sizeof(TIMESTAMP_STRUCT); 
ibPrecision=5; // For DATETIME, SQL_CODE_DATE data 
// precision defaults to 0, but it implies it can be set otherwise. 
ibScale=0;// Only used for DECIMAL or NUMERIC types, otherwise undefined 
 
CheckDescRecord(hdesc1, swDescRec, fType, fSubType, cbLength, ibPrecision,  
ibScale, &tsval, &cbValue, &Indicator, iDescType); 
} 
} 
else 
{ 
// Unable to read record count from descriptor header, 
// can't proceed 
wsprintf(buf,TEXT("\t\tUnable to read record count from descriptor header for  %s"), 
DescTypes[iDescType].szDescName); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_SUCCESS, rc, buf); 
} 
} 
ResetHstmt(&hstmt); 
} 
 
} //TestSetDescRec() 
 
//----------------------------------------------------------------------- 
//      Function:               TestCopyDesc 
//----------------------------------------------------------------------- 
 
void  PASCAL TestCopyDesc(QTSTRUCT * lpqt) 
{ 
SQLRETURN rc=SQL_SUCCESS; 
SQLUSMALLINT iDescType; 
SQLSMALLINT swExpRecCount; 
 
SQLHDESC hdesc1=NULL, hdesc2=NULL; 
PTR rgbValue=NULL; 
TCHARszName[MAX_DESC_BUF]=TEXT(""); 
TCHARszQuery[XLARGEBUFF]=TEXT(""); 
 
 
// Allocate a default descriptor 
rc = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc);   
 
if (RC_SUCCESSFUL(rc)) 
{ 
 
if (!Supported(SQL_API_SQLCOPYDESC)) 
{ 
rc = SQLCopyDesc(hdesc, hdesc1); 
 
if(!FindError(SQL_HANDLE_DESC,szIM001)) 
DISPLAYERROR(szSQLCOPYDESC, szNotSupported); 
RETCHECK(SQL_ERROR, rc,szSQLCOPYDESC); 
} 
else 
{ 
ResetHstmt(&hstmt); 
 
// Perform a select stmt 
wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName); 
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
// For each descriptor type 
for (iDescType=0; iDescType < sizeof(DescTypes)/sizeof(DescTypes[0]); iDescType++) 
{ 
// Get the handle for the automatically allocated descriptor 
rc = SQLGetStmtAttr(hstmt, DescTypes[iDescType].uwDescType, &hdesc1, sizeof(hdesc1), &cbValue);   
RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR); 
 
// Create a descriptor record so we have something to read besides header 
swExpRecCount=CreateDescRecord(hdesc1, hstmt, DescTypes[iDescType].uwDescType); 
 
// Update all descriptor records to new values 
CheckDescriptor(hdesc1, DESC_UPDATE_MODE_WRITE, hstmt, iDescType); 
 
// Copy the descriptor to the newly allocated descriptor 
rc = SQLCopyDesc(hdesc1, hdesc); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_SUCCESS, rc, szSQLCOPYDESC); 
ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, szSQLCOPYDESC); 
 
// Compare each field in the copied descriptor to the original 
if (RC_SUCCESSFUL(rc)) 
CompareDescriptor(hdesc1, hdesc, iDescType, szSQLCOPYDESC); 
} 
 
ResetHstmt(&hstmt); 
} 
 
// Free descriptor handle 
if (hdesc) 
{ 
rc = SQLFreeHandle(SQL_HANDLE_DESC, hdesc);  
RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE); 
} 
} 
 
} //TestCopyDesc() 
 
 
//----------------------------------------------------------------------- 
//      Function:               TestDescDefaults 
//----------------------------------------------------------------------- 
void  PASCAL TestDescDefaults(QTSTRUCT * lpqt) 
{ 
SQLRETURN rc=SQL_SUCCESS; 
 SQLINTEGER cbValue; 
SQLSMALLINT swDescRec; 
SQLUSMALLINT iDescField, iStartField=0, iDescType; 
 
if (Supported(SQL_API_SQLGETDESCFIELD)) 
{ 
 
// Reallocate hstmt to check defaults against 
ResetHstmt(&hstmt); 
 
// For each descriptor type 
for (iDescType=0; iDescType < sizeof(DescTypes)/sizeof(DescTypes[0]); iDescType++) 
{ 
// Get the handle for the descriptor 
rc = SQLGetStmtAttr(hstmt, DescTypes[iDescType].uwDescType, &hdesc, sizeof(hdesc), NULL);   
RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR); 
 
swDescRec=0; 
 
// For each descriptor field, read the value 
for (iDescField=iStartField; iDescField < sizeof(rgDescInfo)/sizeof(rgDescInfo[0]); iDescField++) { 
 
// If we've gone past the header fields, then create a record and check record fields 
if (0 == swDescRec && !rgDescInfo[iDescField].fHeader) { 
iStartField=iDescField; 
// Make sure we're not on the IRD, 'cause you can't modify an IRD 
if (SQL_ATTR_IMP_ROW_DESC != DescTypes[iDescType].uwDescType) 
{ 
// Create a record with all default values 
rc = SQLSetDescField(hdesc, 0, SQL_DESC_COUNT, (SQLPOINTER)1, 
SQL_IS_SMALLINT); 
RETCHECK(SQL_SUCCESS, rc,szSQLSETDESCFIELD); 
 
swDescRec++; 
} 
continue; 
} 
 
// If the field has a default value 
if (rgDescInfo[iDescField].fDefault & DescTypes[iDescType].uwTypeMask) 
{ 
// Read from the field 
rc = SQLGetDescField(hdesc, swDescRec, rgDescInfo[iDescField].uwDescField, 
&DescBuf, sizeof(DescBuf), &cbValue); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETDESCFIELD); 
 
if (RC_SUCCESSFUL(rc)) 
{ 
// Perform the compare 
if (memcmp(DescBuf, &rgDescInfo[iDescField].DefaultVal, cbValue))  
{ 
// Compare error, print message 
wsprintf(buf,TEXT("Error in %s field %s default value"), 
DescTypes[iDescType].szDescName,rgDescInfo[iDescField].szDescFieldName); 
DISPLAYERROR(szSQLGETDESCFIELD, buf); 
} 
} 
} 
} 
} 
} 
} // TestDescDefaults 
  
//----------------------------------------------------------------------- 
//      Function:               TestUseDesc 
//----------------------------------------------------------------------- 
void  PASCAL TestUseDesc(QTSTRUCT * lpqt, FIELDINFO  *rgFields) 
{ 
LPTSTR   pch=NULL; 
SDWORD crow=0; 
TCHARszQuery[XLARGEBUFF]=TEXT(""); 
SQLRETURN rc; 
UWORDrow, icol, paramno; 
SWORDccol; 
TCHAR * rgbMemBuf=NULL, * rgbValue=NULL; 
SDWORD * pcbValueBuf=NULL, * pcbValue=NULL; 
 
if (Supported(SQL_API_SQLSETDESCFIELD)) 
{ 
 
// Test descriptor bindcol 
 
// Reallocate hstmt to set to defaults 
ResetHstmt(&hstmt); 
 
// Perform a select stmt 
wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName); 
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
rc=SQLNumResultCols(hstmt, &ccol); 
RETCHECK(SQL_SUCCESS, rc, szSQLNUMRESULTCOLS); 
 
rc=SQLFreeStmt(hstmt, SQL_CLOSE); // Close the cursor so we can insert  
RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT); 
 
rgbMemBuf=AllocateMemory(ccol*MAX_STRING_SIZE*sizeof(TCHAR)); 
 
if (!rgbMemBuf) 
{ 
DISPLAYERROR(TEXT("Simulate BindCol"),TEXT("Out of memory!")); 
goto ExitUseDesc; 
} 
 
pcbValueBuf=(SDWORD *)AllocateMemory(ccol*sizeof(SDWORD)); 
 
if (!pcbValueBuf) 
{ 
DISPLAYERROR(TEXT("Simulate BindCol"),TEXT("Out of memory!")); 
goto ExitUseDesc; 
} 
 
// Bind a parameter for each column in the result set using descriptors 
paramno=0; 
for (icol=1, rgbValue=rgbMemBuf, pcbValue=pcbValueBuf; 
icol <= ccol; 
icol++, rgbValue+=MAX_STRING_SIZE*sizeof(TCHAR), pcbValue++) 
{ 
pch = qtMakeData(guwRowCount, icol-1, &rgFields[icol-1], rgbValue); 
 
// Field is not READ ONLY 
if(pch)  
{ 
 // Where row and column match and field is nullable, make NULL 
if (icol == guwRowCount && rgFields[icol-1].nullable) 
*pcbValue=SQL_NULL_DATA; 
else 
*pcbValue=SQL_NTS; 
 
paramno++; 
//rc=SQLBindParameter(hstmt, paramno, SQL_PARAM_INPUT, SQL_C_CHAR,  
rc=DescBindParameter(hstmt, paramno, SQL_PARAM_INPUT, SQL_C_CHAR,  
rgFields[icol-1].wSQLType, rgFields[icol-1].precision, 
rgFields[icol-1].scale, rgbValue, 0, pcbValue); 
RETCHECK(SQL_SUCCESS, rc,TEXT("DescBindParameter")); 
} 
} 
 
// Insert the new row.  Note that the inserted row will be checked 
// for accuracy below. 
rc = SQLExecDirect(hstmt, szInsertStmt, SQL_NTS); 
ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_SUCCESS, rc, szSQLEXECDIRECT); 
 
if (RC_SUCCESSFUL(rc)) 
guwRowCount++; 
 
// Perform the select stmt again 
wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName); 
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
// Bind all the columns to char 
for (icol=1, rgbValue=rgbMemBuf, pcbValue=pcbValueBuf; 
icol <= ccol; 
icol++, rgbValue+=MAX_STRING_SIZE*sizeof(TCHAR), pcbValue++) 
{ 
// Bind to next column 
rc = DescBindCol(hstmt, icol, SQL_C_CHAR, rgbValue, MAX_STRING_SIZE*sizeof(TCHAR), pcbValue); 
//rc = SQLBindCol(hstmt, icol, SQL_C_CHAR, rgbValue, MAX_STRING_SIZE*sizeof(TCHAR), pcbValue); 
RETCHECK(SQL_SUCCESS, rc, TEXT("DescBindCol")); 
} 
 
// Fetch all the rows and check the bound value with MakeAData for 
// each column 
for (row=1; rc == SQL_SUCCESS; row++) 
{ 
rc=SQLFetch(hstmt); // Will return SQL_NO_DATA after last row 
 
if (SQL_SUCCESS == rc) 
{ 
 
// Compare all the columns 
for (icol=1, rgbValue=rgbMemBuf, pcbValue=pcbValueBuf; 
icol <= ccol; 
icol++, rgbValue+=MAX_STRING_SIZE*sizeof(TCHAR), pcbValue++) 
{ 
 
CompareWithExpected(rgbValue, pcbValue, row, icol, rgFields); 
} 
} 
else 
ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_NO_DATA, rc, szSQLFETCH); 
 
} 
 
} 
 
ExitUseDesc: 
rc=SQLFreeStmt(hstmt, SQL_CLOSE); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT); 
 
if (rgbMemBuf) 
ReleaseMemory(rgbMemBuf); 
if (pcbValueBuf) 
ReleaseMemory(pcbValueBuf); 
 
 
} // TestUseDesc 
 
//----------------------------------------------------------------------- 
//      Function:               TestEnvAttr 
// 
// Note:Only one environment attribute (SQL_ATTR_OUTPUT_NTS) exists at this 
// time.  The default value is SQL_TRUE. 
// 
//For the Environment attributes we assume support if DM version >= 3.00 
//----------------------------------------------------------------------- 
 
void  PASCAL TestEnvAttr() 
{ 
SQLINTEGERsdwEnvAttr; 
SQLRETURNrc; 
HENVtshenv; 
BOOLfSetSupported = Supported(SQL_API_SQLSETENVATTR), 
fGetSupported = Supported(SQL_API_SQLGETENVATTR); 
 
 
//allocate an enviroment handle 
rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &tshenv); 
RETCHECK(SQL_SUCCESS, rc,szSQLALLOCHANDLE); 
 
 
//------------------------------- 
//-------- SQLSetEnvAttr -------- 
//------------------------------- 
// Set to SQL_FALSE 
rc = SQLSetEnvAttr(tshenv, SQL_ATTR_ODBC_VERSION, (PTR)SQL_OV_ODBC3, 
SQL_IS_UINTEGER); 
 
if(!fSetSupported) 
{ 
if (!FindError(SQL_HANDLE_ENV,szIM001)) 
DISPLAYERROR(szSQLSETENVATTR, szNotSupported); 
 
RETCHECK(SQL_ERROR, rc,szSQLSETENVATTR); 
} 
else 
RETCHECK(SQL_SUCCESS, rc,szSQLSETENVATTR); 
 
if (RC_SUCCESSFUL(rc)) 
{ 
// Read it again 
rc = SQLGetEnvAttr(tshenv, SQL_ATTR_ODBC_VERSION, &sdwEnvAttr, 
sizeof(sdwEnvAttr), NULL); 
 
if(!fGetSupported) 
{ 
if (!FindError(SQL_HANDLE_ENV,szIM001)) 
DISPLAYERROR(szSQLGETENVATTR, szNotSupported); 
 
RETCHECK(SQL_ERROR, rc,szSQLGETENVATTR); 
} 
else 
RETCHECK(SQL_SUCCESS, rc,szSQLGETENVATTR); 
 
if (RC_SUCCESSFUL(rc) && (SQL_OV_ODBC3 != sdwEnvAttr)) 
{ 
// New value wrong 
DISPLAYERROR(szSQLSETENVATTR,TEXT("Unable to set environment attribute SQL_ATTR_ODBC_VERSION to SQL_OV_ODBC3.")); 
} 
} 
 
rc = SQLFreeHandle(SQL_HANDLE_ENV,tshenv); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE); 
 
//------------------------------- 
//-------- SQLGetEnvAttr -------- 
//------------------------------- 
rc = SQLAllocEnv(&tshenv); 
RETCHECK(SQL_SUCCESS, rc,szSQLALLOCENV); 
 
rc = SQLGetEnvAttr(tshenv, SQL_ATTR_ODBC_VERSION, &sdwEnvAttr, 
sizeof(sdwEnvAttr), NULL); 
 
if(!fGetSupported) 
{ 
if (!FindError(SQL_HANDLE_ENV,szIM001)) 
DISPLAYERROR(szSQLGETENVATTR, szNotSupported); 
 
RETCHECK(SQL_ERROR, rc,szSQLGETENVATTR); 
} 
else 
RETCHECK(SQL_SUCCESS, rc,szSQLGETENVATTR); 
 
 
if (RC_SUCCESSFUL(rc) && (SQL_OV_ODBC2 != sdwEnvAttr)) 
{ 
// Default value wrong 
DISPLAYERROR(szSQLGETENVATTR,TEXT("Value was not SQL_OV_ODBC3!")); 
} 
 
 
rc = SQLFreeHandle(SQL_HANDLE_ENV,tshenv); 
RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE); 
 
} //TestEnvAttr() 
 
 
//----------------------------------------------------------------------- 
//    Function: GetRowCnt 
// 
//Get the row count of the table lpqt->szTalbeName 
//----------------------------------------------------------------------- 
SWORD  PASCAL GetRowCnt(QTSTRUCT  *lpqt) 
{ 
 SWORD sRowCnt; 
RETCODErc; 
 
// free the statment handle for a fresh start 
FreeStmt(SQL_DROP); 
 
AllocHstmt(); 
 
//get row count for the table 
wsprintf(lpqt->sz,TEXT("select count(*) from %s"), lpqt->szTableName); 
 
rc = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); 
 
rc = SQLFetch(hstmt); 
RETCHECK(SQL_SUCCESS, rc,szSQLFETCH); 
 
rc = SQLGetData(hstmt,1, SQL_C_SSHORT, &sRowCnt, sizeof(sRowCnt), NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); 
 
FreeStmt(SQL_CLOSE); 
 
return sRowCnt; 
}//GetRowCount 
 
 
//----------------------------------------------------------------------- 
//    Function: InsertOneRow 
// 
//Insert one row into the table. 
// 
//lpqt:temp place to hold data genrated 
//rgFields:hold info about each data type in the dbs 
//cTypes;the count of data types 
//lpd:buffer used for SQLBindParam 
//cSeed;the seed used to generate data 
//fFreeHsmt:if the hstmt should be freed    
// 
//Return TRUE: the insertion was successful 
// FALSE: otherwise 
//----------------------------------------------------------------------- 
BOOL  PASCAL InsertOneRow(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes, 
DSTRUCT  *lpd,UWORD cSeed,BOOL fFreeHstmt) 
{ 
RETCODE  rc; 
UWORD    w; 
UWORD    ind; 
LPTSTR    pch=NULL; 
SQLHDESChdesc; 
   SQLSMALLINT      fParamType = SQL_PARAM_INPUT; 
TCHARszDataItem[150]; 
 
 
//prepare the insert statement 
rc = SQLPrepare(hstmt, szInsertStmt, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE); 
 
//going through each data type, call SQLBindParam 
for(ind = 0, w = 0; ind < cTypes; ind++)  
{ 
 
//make data according to data type description in rgFields[], cSeed is the seed 
pch = qtMakeData(cSeed,ind,&rgFields[ind], szDataItem); 
 
//if the data type is READ_ONLY, skip 
if(!pch)  
continue; 
 
//populate the NULL data 
if(*pch)  
{ 
lstrcpy(lpd[w].data, pch); 
lpd[w].cb = SQL_NTS; 
} 
else  
{ 
lstrcpy(lpd[w].data,TEXT("")); 
lpd[w].cb = SQL_NULL_DATA; 
} 
 
if (g_f3XDriver && Supported(SQL_API_SQLSETDESCFIELD)) 
//if (0)//DEBUG 
{ 
//bind the data buffer in lpd[] to each column of the table 
rc = SQLBindParam(hstmt, (SQLSMALLINT)(w+1),SQL_C_TCHAR, rgFields[ind].wSQLType, 
rgFields[ind].precision, rgFields[ind].scale, 
&lpd[w].data, &lpd[w].cb); 
RETCHECK(SQL_SUCCESS, rc,szSQLBINDPARAM); 
 
if(rc!= SQL_SUCCESS) 
return FALSE; 
 
//get the driver parameter descriptor handle 
rc = SQLGetStmtAttr(hstmt,SQL_ATTR_IMP_PARAM_DESC, &hdesc, sizeof(hdesc),NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR); 
if(rc!= SQL_SUCCESS) 
return FALSE; 
 
//set the parameter type field in the descriptor 
rc = SQLSetDescField(hdesc, (SQLSMALLINT)(w+1), SQL_DESC_PARAMETER_TYPE,  
(PTR)fParamType, sizeof(fParamType)); 
RETCHECK(SQL_SUCCESS, rc,szSQLSETDESCFIELD); 
 
} 
else 
{ 
rc = SQLBindParameter(hstmt, (UWORD)(w+1),SQL_PARAM_INPUT,SQL_C_TCHAR,  
rgFields[ind].wSQLType,rgFields[ind].precision,  
rgFields[ind].scale,&lpd[w].data, 100, &lpd[w].cb); 
 
RETCHECK(SQL_SUCCESS, rc,szSQLBINDPARAMETER); 
 
if(rc!= SQL_SUCCESS) 
return FALSE; 
} 
 
 
//go on to next column 
w++; 
} 
 
// insert a row  
rc = SQLExecute(hstmt);  
RETCHECK(SQL_SUCCESS, rc,szSQLEXECUTE); 
if(rc!= SQL_SUCCESS) 
return FALSE; 
 
//free the hstmt if required 
if(fFreeHstmt) 
{ 
if (FreeStmt(SQL_CLOSE)) 
return FALSE; 
 
} 
 
return TRUE; 
 
}//InsertOneRow 
 
//----------------------------------------------------------------------- 
//    Function: ExecEndTran 
// 
//Execute EndTran statement, return the row count of the table 
//----------------------------------------------------------------------- 
SWORD  PASCAL ExecEndTran(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes, 
DSTRUCT  *lpd,SQLSMALLINT fHandleType, SQLSMALLINT fMode, 
UWORD cSeed) 
{ 
  RETCODE rc; 
 
//does not free the hstmt 
if(!InsertOneRow(lpqt,rgFields,cTypes,lpd,cSeed, FALSE)) 
return (INSERT_FAIL); 
 
switch(fHandleType) 
{ 
case SQL_HANDLE_ENV: 
rc= SQLEndTran(fHandleType,henv,fMode); 
break; 
case SQL_HANDLE_DBC: 
rc= SQLEndTran(fHandleType,hdbc,fMode); 
break; 
default: 
DISPLAYERROR(TEXT("ExecEndTran"),TEXT("Did not recieve correct handle type")); 
break; 
} 
RETCHECK(SQL_SUCCESS, rc,szSQLENDTRAN); 
 
if (SQL_COMMIT == fMode && SQL_SUCCESS == rc) 
guwRowCount++;// We inserted a row, increment global row count 
 
//free the hstmt handle 
FreeStmt(SQL_CLOSE); 
 
return(GetRowCnt(lpqt)); 
} //ExecEndTran 
 
//----------------------------------------------------------------------- 
//    Function: TestEndTran 
// 
//Test the SQLEndTran for SDK 3.0 
//----------------------------------------------------------------------- 
void  PASCAL TestEndTran(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes, 
DSTRUCT  *lpd) 
{ 
SWORDi; 
RETCODE rc; 
SWORDsTXN; 
SWORDsRowCnt_Pre; 
SWORDsRowCnt_Aft; 
SQLSMALLINT fHandleType[]={SQL_HANDLE_ENV, SQL_HANDLE_DBC}; 
SDWORDcbValue=0; 
 
//check if transaction is supported 
rc = SQLGetInfo(hdbc, SQL_TXN_CAPABLE, &sTXN, sizeof(sTXN), NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); 
 
//check both henv and hdbc handle 
for(i=0; i<=1; i++) 
{  
 
//get the row count of the table 
sRowCnt_Pre = GetRowCnt(lpqt); 
 
//check if SQLEndTran is supported 
if(Supported(SQL_API_SQLENDTRAN)) 
{ 
if(sTXN != SQL_TC_NONE) 
{ 
//set the autocommit to off 
SetConnectionAttributes(hdbc,SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); 
 
//insert one row, and call SQLEndTran to roll back the transction 
sRowCnt_Aft = ExecEndTran(lpqt,rgFields,cTypes,lpd,fHandleType[i],SQL_ROLLBACK,(UWORD)(guwRowCount)); 
 
//the row count should be the same 
if(sRowCnt_Aft != sRowCnt_Pre) 
DISPLAYERROR(szSQLENDTRAN,TEXT("Did not Roll Back the insert transaction")); 
} 
 
//insert one row, and call SQLEndTran to commit the transction 
sRowCnt_Aft = ExecEndTran(lpqt,rgFields,cTypes,lpd,fHandleType[i],SQL_COMMIT,(UWORD)(guwRowCount)); 
 
//the row count should be increased by 1 
if(sRowCnt_Aft != (sRowCnt_Pre+1) ) 
DISPLAYERROR(szSQLENDTRAN,TEXT("Did not commit the insert transaction")); 
 
if( sTXN != SQL_TC_NONE) 
{ 
//set the autocommit to off 
SetConnectionAttributes(hdbc,SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); 
} 
 
}//end of the situation where SQLEndTran is supported 
else 
{ 
 
switch(fHandleType[i]) 
{ 
case SQL_HANDLE_ENV:  
rc= SQLEndTran(fHandleType[i],henv,SQL_COMMIT); 
break; 
case SQL_HANDLE_DBC:  
rc= SQLEndTran(fHandleType[i],hdbc,SQL_ROLLBACK); 
break; 
} 
 
//check error msg 
if(!FindError(fHandleType[i],szIM001)) 
DISPLAYERROR(szSQLENDTRAN,TEXT("Did not return not Supported Message")); 
 
RETCHECK(SQL_ERROR, rc,szSQLENDTRAN); 
 
//free the hstmt handle 
FreeStmt(SQL_CLOSE); 
 
}//end of error msg checking 
 
}//end of the loop to check both henv and hdbc 
 
// Commit the transaction started in GetRowCnt inside ExecEndTran 
rc= SQLEndTran(SQL_HANDLE_ENV,henv,SQL_COMMIT); 
RETCHECK(SQL_SUCCESS, rc,szSQLENDTRAN); 
 
SetConnectionAttributes(hdbc,SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); 
 
//free the hstmt handle 
FreeStmt(SQL_CLOSE); 
 
} // TestEndTran() 
 
 
//----------------------------------------------------------------------- 
//    Function: TestBindParam 
// 
//Test the SQLBindParam for SDK 3.0 
//----------------------------------------------------------------------- 
void  PASCAL TestBindParam(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes, 
DSTRUCT  *lpd) 
{ 
 RETCODE rc; 
SQLINTEGERcbValue = SQL_NTS; 
TCHARszDataItem[150]; 
 
if(Supported(SQL_API_SQLBINDPARAM)) 
{ 
//test SQLBindParam by inserting one row, do not free the hstmt handle 
if (InsertOneRow(lpqt,rgFields,cTypes,lpd,(UWORD)(guwRowCount),FALSE)) 
guwRowCount++; // We've inserted a row 
} 
else 
{ 
 //prepare the insert statement 
rc = SQLPrepare(hstmt, szInsertStmt, SQL_NTS); 
RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE); 
 
//make data according to data type description in rgFields[0], cSeed is the seed 
qtMakeData(cTypes+1,0,&rgFields[0],szDataItem); 
 
//try to bind lpqt->szDataItem to the first column of the table 
rc = SQLBindParam(hstmt,1,SQL_C_TCHAR, rgFields[0].wSQLType, rgFields[0].precision, 
rgFields[0].scale,lpqt->szDataItem, &cbValue); 
 
//check error msg 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(szSQLBINDPARAM,TEXT("Did not return Not Supported Message")); 
 
RETCHECK(SQL_ERROR, rc,szSQLBINDPARAM); 
} 
 
//free the hstmt handle 
FreeStmt(SQL_CLOSE); 
 
} // TestBindParam() 
 
 
 
 
 
 
//----------------------------------------------------------------------- 
//    Function: TestFetchScroll 
// 
//Test the SQLFetchScroll for SDK 3.0 
//----------------------------------------------------------------------- 
 
void PASCAL TestFetchScroll(QTSTRUCT *lpqt) 
{ 
RETCODErc=SQL_SUCCESS; 
TCHARszSave[MAX_QUERY_SIZE]; 
DWORDdwLen=0; 
SDWORDcbValue=0; 
 
/* check if SQLGetFunctions says your API is supported */ 
if(!Supported( SQL_API_SQLFETCHSCROLL)) 
{ 
/* Call your 3.0 API here and verify that the correct state is returned */ 
rc = SQLFetchScroll(hstmt,SQL_FETCH_FIRST, 0); 
if(!FindError(SQL_HANDLE_STMT,szIM001)) 
DISPLAYERROR(szSQLFETCHSCROLL, szNotSupported); 
RETCHECK(SQL_ERROR, rc, szSQLFETCHSCROLL); 
} 
else 
{ 
ResetHstmt(&hstmt); 
 
/* Valid Testing of SQLFetchScroll */ 
SelectFromTable(lpqt); 
 
rc = SQLBindCol(hstmt, 1, SQL_C_TCHAR, lpqt->sz, MAX_BIND_ARRAY_ELEMENT, 
&cbValue); 
RETCHECK(SQL_SUCCESS, rc, szSQLBINDCOL); 
 
rc = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 3); 
RETCHECK(SQL_SUCCESS, rc, szSQLFETCHSCROLL); 
lstrcpy(szSave,lpqt->sz); 
 
rc = SQLFetchScroll(hstmt, SQL_FETCH_PRIOR, 1); 
RETCHECK(SQL_ERROR, rc, szSQLFETCHSCROLL); 
 
rc = SQLFetchScroll(hstmt, SQL_FETCH_FIRST, 0); 
RETCHECK(SQL_ERROR, rc, szSQLFETCHSCROLL); 
 
rc = SQLFetchScroll(hstmt, SQL_FETCH_LAST, 0); 
RETCHECK(SQL_ERROR, rc, szSQLFETCHSCROLL); 
 
rc = SQLFreeStmt(hstmt, SQL_CLOSE); 
RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT); 
 
} 
 
//free the hstmt handle 
FreeStmt(SQL_CLOSE); 
 
} // TestFetchScroll() 
 
 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               qtDisplayError                           */ 
/*-----------------------------------------------------------------------*/ 
 
void  PASCAL qtDisplayError(LPTSTR szFunction, LPTSTR buf, LPTSTR szFile, int iLine) 
{ 
TCHAR szTmp[MAX_STRING_SIZE]; 
 
szWrite(TEXT(""), TRUE); 
szWrite(TEXT("\t\t\t"), FALSE); 
szWrite(szFunction, FALSE); 
szWrite(TEXT("  FAILED"), TRUE); 
szWrite(TEXT("\t\t\t"), FALSE); 
szWrite(buf, TRUE); 
 
wsprintf(szTmp,TEXT("\t\t\t%s: %d"), szFile, iLine); 
szWrite(szTmp, TRUE); 
 
szWrite(TEXT("\t\t\t  --------  "), TRUE); 
 
lpSI->failed++; 
 
return; 
} 
 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               qtMakeData                               */ 
/*-----------------------------------------------------------------------*/ 
 
LPTSTR  PASCAL qtMakeData(int row, int col,FIELDINFO  *rgField, LPTSTR buf) 
{ 
if(rgField->fAutoUpdate) 
return NULL; 
 
if(rgField->nullable && (row==col))  
{ 
lstrcpy(buf,TEXT("")); 
return buf; 
} 
 
switch(rgField->wSQLType) { 
case SQL_CHAR: 
case SQL_VARCHAR: 
case SQL_LONGVARCHAR: 
case SQL_BINARY: 
case SQL_VARBINARY: 
case SQL_LONGVARBINARY: 
if(rgField->precision < 4) 
wsprintf(buf,TEXT("%d"), 1); 
else 
wsprintf(buf,TEXT("%d%d"), row, row); 
break; 
case SQL_DECIMAL: 
case SQL_NUMERIC: 
case SQL_REAL: 
case SQL_FLOAT: 
case SQL_DOUBLE: 
if(row == 2 && !rgField->fUnsigned) /* make the second row negative for variety */ 
wsprintf(buf,TEXT("-%d.%d"), row, row); 
else 
wsprintf(buf,TEXT("%d.%d"), row, row); 
break; 
 
case SQL_BIT: 
if(row > 2) 
wsprintf(buf,TEXT("%d"), 1); 
else 
wsprintf(buf,TEXT("%d"), 0); 
 
break; 
 
case SQL_SMALLINT: 
case SQL_INTEGER: 
case SQL_TINYINT: 
case SQL_BIGINT: 
if(row == 2 && !rgField->fUnsigned) /* make the second row negative for variety */ 
wsprintf(buf,TEXT("-%d"), row); 
else 
wsprintf(buf,TEXT("%d"), row); 
break; 
 
case SQL_TIME: 
case SQL_TYPE_TIME: 
wsprintf(buf,TEXT("{t '01:%02d:%02d'}"), row % 60, row % 60); 
break; 
case SQL_DATE: 
case SQL_TYPE_DATE: 
wsprintf(buf,TEXT("{d '1994-%02d-%02d'}"), (row % 12) + 1, (row % 30) + 1); 
break; 
case SQL_TIMESTAMP: 
case SQL_TYPE_TIMESTAMP: 
wsprintf(buf,TEXT("{ts '1994-%02d-%02d 01:%02d:%02d'}"), (row % 12) + 1, (row % 30) + 1, row % 60, row % 60); 
break; 
} 
return buf; 
} 
 
 
 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               TestNumResCols                           */ 
/*-----------------------------------------------------------------------*/ 
 
VOID PASCAL TestNumResCols(SDWORD cColsSelected,QTSTRUCT *lpqt) 
{ 
RETCODErc=SQL_SUCCESS; 
SWORDwNum; 
 
SelectFromTable(lpqt); 
 
rc = SQLNumResultCols(hstmt, &wNum); 
RETCHECK(SQL_SUCCESS, rc,szSQLNUMRESULTCOLS); 
 
if(wNum != cColsSelected) 
DISPLAYERROR(szSQLNUMRESULTCOLS,TEXT("incorrect value returned")); 
 
FreeStmt(SQL_CLOSE); 
 
} /* TestNumResCols() */ 
 
 
 
/*-----------------------------------------------------------------------*/ 
/*      Function:               TestNumResCols                           */ 
/*-----------------------------------------------------------------------*/ 
 
VOID PASCAL TestCursorName(QTSTRUCT *lpqt) 
{ 
RETCODErc=SQL_SUCCESS; 
TCHARszCursorName[MEDBUFF]; 
SWORDcb=0; 
 
SelectFromTable(lpqt); 
 
/* the cursor name should be created by the driver since one was*/ 
/* not specified*/ 
 
rc = SQLGetCursorName(hstmt, szCursorName, MAX_STRING_SIZE, &cb); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETCURSORNAME); 
 
if(cb > MAX_STRING_SIZE) 
{ 
DISPLAYERROR(szSQLGETCURSORNAME,TEXT("invalid cb")); 
cb = MAX_STRING_SIZE; 
} 
 
/* don't check the name itself, just make sure that*/ 
/*something was returned */ 
if(!*szCursorName)  
DISPLAYERROR(szSQLGETCURSORNAME,TEXT("no name returned")); 
 
FreeStmt(SQL_CLOSE); 
 
} /* TestCursorName() */ 
 
 
//----------------------------------------------------------------------- 
//      Function:               GetDMVersion 
//----------------------------------------------------------------------- 
 
UWORD PASCAL GetDMVersion() 
{ 
RETCODErc=SQL_SUCCESS; 
TCHARszNum[MAX_NUM_BUFFER]; 
 
rc = SQLGetInfo(hdbc, SQL_ODBC_VER, &szNum, MAX_NUM_BUFFER, NULL); 
RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); 
 
return((UWORD)_ttoi(_tcstok(szNum,TEXT(".")))); 
 
} /* GetDMVersion() */ 
 
 
//----------------------------------------------------------------------- 
//      Function:               DisplayTestName 
//----------------------------------------------------------------------- 
 
VOID PASCAL DisplayTestName(UWORD i) 
{ 
szWrite(szBLANKLINE,TRUE); 
szWrite(szTAB,FALSE); 
szWrite(iTestNames[i-1], TRUE); 
 
} /* DisplayTestName() */ 
 
 
 
/***************************  External Interfaces  *************************/ 
/*  These functions are called by Gator to envoke the tests.               */ 
/***************************************************************************/ 
 
BOOL CALLBACK AutoTestName(LPTSTR szName, UINT  * cbTestCases) 
{ 
static TCHAR szTestName[] = TEXT("Quick Test"); 
 
lstrcpy(szName, szTestName); 
 
*cbTestCases = sizeof(iTestNames)/sizeof(LPTSTR); 
 
return TRUE; 
} 
 
//----------------------------------------------------------------------- 
//      Function:               AutoTestDesc 
//      Purpose:                        Provides gator with a list of tests which can be run. 
//----------------------------------------------------------------------- 
BOOL CALLBACK AutoTestDesc(UWORD iTest, LPTSTR szName, LPTSTR szDesc) 
{ 
 
UWORD len=0; 
 
if (iTest > (sizeof(iTestNames)/sizeof(LPTSTR))) 
return FALSE; 
 
if (szName) 
     lstrcpy(szName,iTestNames[iTest-1]); 
 
if (szDesc) 
        lstrcpy(szDesc,TEXT(" ")); 
 
return TRUE; 
 
} 
 
//----------------------------------------------------------------------- 
//      Function:               AutoTestFunc 
//----------------------------------------------------------------------- 
 
void CALLBACK AutoTestFunc(lpSERVERINFO pTestSource) 
{ 
 
RETCODErc; 
UWORDcTypes; 
UDWORDdwLen; 
UWORDfIndex; 
SDWORDcColsSelected; 
FIELDINFO*rgFields = (FIELDINFO  *)AllocateMemory(sizeof(FIELDINFO) * MAX_TYPES_SUPPORTED); 
QTSTRUCT*lpqt = (QTSTRUCT  *)AllocateMemory(sizeof (QTSTRUCT)); 
DSTRUCT*lpd = (DSTRUCT  *)AllocateMemory(sizeof (DSTRUCT) * MAX_TYPES_SUPPORTED); 
UWORDuDMVer; 
SDWORDcbValue=0; 
TCHARszAPI[MEDBUFF]; 
UWORDi; 
TCHARszState[100]=TEXT(""), 
szErrMsg[XLARGEBUFF]=TEXT(""); 
 
 
lpSI = pTestSource; 
lpSI->failed = 0; 
henv = NULL; 
hdbc = NULL; 
hstmt = NULL; 
hdesc = NULL; 
 
if(lpSI->szValidServer0) 
{ 
if (Connect(lpSI,lpqt)) 
goto ErrorRet; 
} 
else  
{ 
henv = lpSI->henv; 
hdbc = lpSI->hdbc; 
 
rc = SQLSetConnectOption(hdbc,SQL_ODBC_CURSORS,dwLen); 
lstrcpy(szAPI,szSQLSETCONNECTOPTION); 
 
if(RETCHECK(SQL_SUCCESS, rc,szAPI)) 
lpSI->vCursorLib = dwLen; 
} 
 
 uDMVer=GetDMVersion(); 
 
fIndex=CheckConformanceLevel(); 
 
fBindParameter=Supported(SQL_API_SQLBINDPARAMETER); 
fDiagRecSupported=Supported(SQL_API_SQLGETDIAGREC); 
fDiagFieldSupported=Supported(SQL_API_SQLGETDIAGFIELD); 
 
 
AllocHstmt(); 
 
if (!(cTypes=GetTypeInfo(rgFields,lpqt))) 
goto ErrorRet; 
 
guwRowCount=cTypes+1;// Extra row inserted with DAE. 
 
// cTypes=20;  //DEBUG 
 
/* build create statement */ 
if (BuildCreateStmt(lpqt,rgFields,cTypes)) 
goto ErrorRet; 
 
/* put together the insert statement, and set the parameters   */ 
/* parameters are only set the first time through, after which */ 
/* the contents of the pointers is changed                     */ 
if (BuildInsertStmt(lpqt, rgFields,cTypes,lpd,&cColsSelected,fBindParameter)) 
goto ErrorRet; 
 
CreateParamQuery(lpqt,rgFields,cTypes); 
 
for(i=1;i <= (sizeof(iTestNames)/sizeof(LPTSTR));i++) 
{ 
lpqt->sz[0] = TEXT('\0'); 
 
if(GETBIT(pTestSource->rglMask,i)) 
{ 
/* Display current Test */ 
DisplayTestName(i); 
 
switch(i) 
{ 
case 1: 
TestConnectionOptions(); 
break; 
case 2: 
TestStmtOptions(); 
break; 
case 3: 
TestCursorName(lpqt); 
break; 
case 4: 
TestData(lpqt,rgFields,cTypes,lpd); 
break; 
case 5: 
TestNumResCols(cColsSelected,lpqt); 
break; 
case 6: 
TestMetaData(lpSI,lpqt,rgFields,cTypes); 
break; 
case 7: 
TestSearchedQuery(lpqt,rgFields,cTypes,lpd,fBindParameter); 
break; 
case 8: 
TestLargeQuery(lpqt,rgFields,cTypes,lpd); 
break; 
case 9: 
TestSQLTables(lpqt); 
break; 
case 10: 
TestSQLStatistics(lpqt,rgFields,cTypes,lpd,fIndex); 
break; 
case 11: 
TestSQLSpecialCols(lpqt); 
break; 
case 12: 
TestLikeQuery(lpqt,rgFields,cTypes,lpd); 
break; 
case 13: 
TestSQLForeignKeys(lpqt); 
break; 
case 14: 
TestSQLBrowseConnect(lpSI); 
break; 
case 15: 
TestSQLDataSources(); 
break; 
case 16: 
TestSQLDrivers(); 
break; 
 case 17: 
TestSQLMoreResults(lpqt); 
break; 
 case 18: 
TestSQLNativeSQL(lpqt); 
break; 
case 19: 
TestSQLDescribeParam(lpqt); 
break; 
case 20: 
TestSQLNumParams(lpqt); 
break; 
case 21: 
TestSQLParamOptions(lpqt); 
break; 
case 22: 
TestSQLPrimaryKeys(lpqt); 
break; 
case 23: 
TestSQLProcedures(); 
break; 
case 24: 
TestSQLTablePrivileges(); 
break; 
case 25: 
TestSQLColumnPrivileges(lpqt); 
break; 
case 26: 
TestSQLSetScrollOptions(); 
break; 
case 27: 
TestExtendedFetch(lpqt,rgFields,cTypes); 
break; 
case 28: 
TestOJCap(lpqt); 
break; 
case 29: 
TestSQLSetConnectAttr(); 
break; 
case 30: 
TestSQLSetStmtAttr(); 
break; 
case 31: 
TestThreading(lpSI,lpqt,rgFields); 
break; 
case 32: 
TestGetDescField(lpqt); 
break; 
case 33: 
TestSetDescField(lpqt); 
break; 
case 34: 
TestGetDescRec(lpqt); 
break; 
case 35: 
TestSetDescRec(lpqt); 
break; 
case 36: 
TestCopyDesc(lpqt); 
break; 
case 37: 
TestDescDefaults(lpqt); 
break; 
case 38: 
TestUseDesc(lpqt, rgFields); 
break; 
case 39: 
TestEnvAttr(); 
break; 
case 40: 
TestEndTran(lpqt,rgFields,cTypes,lpd); 
break; 
case 41: 
TestBindParam(lpqt,rgFields,cTypes,lpd); 
break; 
case 42: 
TestQuickRebind(lpqt,rgFields,cTypes,lpd); 
break; 
case 43: 
TestFetchScroll(lpqt); 
break; 
case 44: 
TestDiagRec(); 
break; 
case 45: 
TestDiagField(); 
break; 
case 46: 
TestMixedAnsiUnicode(lpqt); 
break; 
 
} /* switch(i) */ 
 
} /* if(GETBIT(pTestSource->rglMask,i)) */ 
 
} 
 
//the end of test cases for ODBC SDK 3.0 
 
/* finished testing, clean up */ 
CleanUp(lpd,lpqt,rgFields,lpqt->szTableName,FALSE,lpSI->szValidServer0); 
 
szWrite(szBLANKLINE,TRUE); 
 
lpSI->cErrors = lpSI->failed; 
 
return; 
 
ErrorRet: 
/* a failure in an ODBC function that prevents completion of the*/ 
/* test - for example, connect to the server */ 
 
szWrite(TEXT("\t\t *** Unrecoverable Quick Test FAILURE ***"), TRUE); 
 
/* finished testing, clean up */ 
CleanUp(lpd,lpqt,rgFields,lpqt->szTableName,FALSE,lpSI->szValidServer0); 
 
lpSI->cErrors = ABORT; 
 
return; 
}