//--------------------------------------------------------------------------------------- // // 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 #define _tcscpy strcpy #define _tcstok strtok #define _ttoi atoi #define _ttol atol #define _tcstoul strtoul #define _tcstod strtod #define _tcslen strlen #define _tcsncmp strncmp #define _tcscmp strcmp #define _tcscat strcat #define _tcsnccmp strncasecmp #define _tstrtime(x) timgtime(x) #define min(x,y) ((x>y)?(y):(x)) #define _sntprintf snprintf #define _tcsnccat strncat #define _tcschr strchr #define _ltot(v,s,r) sprintf(s,"%d",v) #define _itot(v,s,r) sprintf(s,"%d",v) #define _tcsicmp strcasecmp #define _tcsstr strstr #include "autotest.h" #include #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_MALLOC_H #include #elif HAVE_SYS_MALLOC_H #include #endif #include #include #include // #include #include "sql.h" #include "sqlext.h" #include "quiktest.h" #define LONG int #define UWORD unsigned short #define LPBYTE char* #define HANDLE void* #define INFINITE -1 char *timgtime(char *s) { time_t tim = time( NULL ); return strftime( s, 20, "%H%M%S", localtime( &tim )); } //-------------------------------------------------------------------------------------- // static //-------------------------------------------------------------------------------------- static CHAR 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 szBrowseNotSupported = TEXT("Browse Connect is not supported with Connection Pooling on"); 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 { SWORD fHandleType; SQLHANDLE hHandle; } 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 */ /*--------------------------------------------------------------------------------------*/ lpSERVERINFO lpSI= NULL; UWORD fBindParameter=FALSE, fDiagRecSupported=FALSE, fDiagFieldSupported=FALSE, uDriverODBCVer=0; UWORD guwRowCount=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]; SQLCHAR buf[MAX_STRING_SIZE]; SQLCHAR szParamName[MAX_STRING_SIZE]=TEXT("Parameter Name"); struct tagDescType { SQLUSMALLINT uwDescType; SQLUSMALLINT uwTypeMask; CHAR 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 ID Field Name Header Gettable Settable fDefault New Value Default Value Data Size Data 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_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_TYPE, TEXT("SQL_DESC_TYPE"), FALSE, DESC_ALL, DESC_MOST, DESC_AD, SQL_DATETIME, SQL_C_DEFAULT, 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, }; BOOL g_f3XDriver=FALSE; //the insert statement buffer to hold the insert statement CHAR szInsertStmt[MAX_STRING_SIZE]; /*----------------------------------------------------------------------- // Function: Supported //-----------------------------------------------------------------------*/ UWORD Supported(UWORD uwSQLFunc) { UWORD fLevel2=FALSE; RETCODE rc=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, CHAR* 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 BinToHex(PTR rgbValue, SWORD cbValue, LPTSTR szHexString) { UWORD ib; LPTSTR pch; CHAR rgchDigits[] = TEXT("0123456789ABCDEF"); _tcscpy(szHexString, TEXT("0x")); if(cbValue > (MAX_STRING_SIZE - 3)/2 || cbValue < 0) cbValue = (MAX_STRING_SIZE - 3)/2; pch = &szHexString[_tcslen(szHexString)]; for(ib=0; ib < cbValue; ib++) { *pch = rgchDigits[((LPBYTE)rgbValue)[ib] >> 4]; pch ++; *pch++ = rgchDigits[((LPBYTE)rgbValue)[ib] & 0xF]; } *pch = TEXT('\0'); } /* BinToHex() */ /*-----------------------------------------------------------------------*/ /* Function: SearchForError */ /*-----------------------------------------------------------------------*/ int SearchForError(HENV henv, HDBC hdbc,HSTMT hstmt,LPTSTR szFindState) { CHAR buf[MAX_STRING_SIZE]; RETCODE rc; CHAR 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 = _tcscmp(szState, szFindState) == 0; } return(found); } /* SearchForError() */ /*-----------------------------------------------------------------------*/ /* Function: szWrite */ /*-----------------------------------------------------------------------*/ VOID szWrite(LPTSTR szStr, BOOL fNewLine) { szLogPrintf(lpSI, FALSE, szStr); if(fNewLine) szLogPrintf(lpSI, FALSE, TEXT("\r\n")); } /*-----------------------------------------------------------------------*/ /* Function: GetErrors */ /*-----------------------------------------------------------------------*/ VOID GetErrors(HENV henv,HDBC hdbc,HSTMT hstmt) { CHAR buf[MAX_ERROR_SIZE]; CHAR largebuf[COMBINED_SIZE]; CHAR 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)) { sprintf(largebuf,TEXT("\t\t\tState: %s"), szState); szWrite(largebuf, TRUE); sprintf(largebuf,TEXT("\t\t\tError: %s"), buf); szWrite(largebuf, TRUE); } } /* GetErrors() */ /*-----------------------------------------------------------------------*/ /* Function: GetDiagRecs */ /*-----------------------------------------------------------------------*/ VOID GetDiagRecs(SWORD fHandleType,SQLHANDLE hHandle) { CHAR szMessageText[XLARGEBUFF]=TEXT(""), szBuff[XLARGEBUFF]=TEXT(""); CHAR szSQLState[100]=TEXT(""); RETCODE rc=SQL_SUCCESS; SWORD irecRecNumber=0; SDWORD fNativeError=0; SWORD cchBufferLength=sizeof(szMessageText)/sizeof(CHAR), cbTextLength=0; SDWORD sdNumRecs=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,cchBufferLength,&cbTextLength); if (RC_SUCCESSFUL(rc)) { sprintf(szBuff,TEXT("\t\t\tState: %s"), szSQLState); szWrite(szBuff, TRUE); sprintf(szBuff,TEXT("\t\t\tError: %s"), szMessageText); szWrite(szBuff, TRUE); } } } /* GetErrors() */ /*-----------------------------------------------------------------------*/ /* Function: DisplayAllErrors */ /*-----------------------------------------------------------------------*/ void 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: RetcodeToCHAR */ /*-----------------------------------------------------------------------*/ LPTSTR RetcodeToCHAR(RETCODE retcode, LPTSTR buf) { switch (retcode) { case SQL_SUCCESS: _tcscpy (buf,TEXT("SQL_SUCCESS")); break; case SQL_ERROR: _tcscpy (buf,TEXT("SQL_ERROR")); break; case SQL_SUCCESS_WITH_INFO: _tcscpy (buf,TEXT("SQL_SUCCESS_WITH_INFO")); break; case SQL_NO_DATA_FOUND: _tcscpy (buf,TEXT("SQL_NO_DATA_FOUND")); break; case SQL_NEED_DATA: _tcscpy (buf,TEXT("SQL_NEED_DATA")); break; case SQL_INVALID_HANDLE: _tcscpy (buf,TEXT("SQL_INVALID_HANDLE")); break; case SQL_STILL_EXECUTING: _tcscpy (buf,TEXT("SQL_STILL_EXECUTING")); break; default: _tcscpy(buf,TEXT("UNKNOWN rc")); } return buf; } //----------------------------------------------------------------------- // Function: ReturnCheck //----------------------------------------------------------------------- int ReturnCheck(RETCODE retExpected, RETCODE retReceived, LPTSTR szFunction, LPTSTR szFile, int iLine,BOOL fDiag) { CHAR 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(RetcodeToCHAR(retExpected, buf), TRUE); szWrite(TEXT("\t\t\tReceived: "), FALSE); szWrite(RetcodeToCHAR(retReceived, buf), TRUE); if (!fDiag) DisplayAllErrors(); sprintf(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 ErrsHandle(SWORD fHandleType,SQLHANDLE hHandle, RETCODE retExpected, RETCODE retReceived, LPTSTR szFunction, LPTSTR szFile, int iLine,BOOL fDiag) { CHAR 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(RetcodeToCHAR(retExpected, buf), TRUE); szWrite(TEXT("\t\t\tReceived: "), FALSE); szWrite(RetcodeToCHAR(retReceived, buf), TRUE); if (!fDiag) GetDiagRecs(fHandleType,hHandle); sprintf(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 FindError(SWORD fHandleType, LPTSTR szFindState) { SQLHANDLE handle = SQL_NULL_HANDLE; SWORD irec; CHAR szErrorMsg[SQL_MAX_MESSAGE_LENGTH]; RETCODE rc; CHAR 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(_tcscmp(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; CHAR szExpBuf[MAX_STRING_SIZE]=TEXT(""); CHAR * 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; CHAR * 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_REAL: bCompare=(fabs(_tcstod(rgbValue, &stopstr) - _tcstod(pstr, &stopstr)) <= fabs((1/pow(10,7))*_tcstod(rgbValue, &stopstr))); break; case SQL_FLOAT: 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+_tcslen(TEXT("{ts '")); // Replace second ' with '\0' ' _tcstok(pstr, TEXT("'")); if (_tcslen(rgbValue) > _tcslen(TEXT("1994-10-10 10:00:00"))) _tcscat(pstr, TEXT(".000")); bCompare=(!_tcsncmp(rgbValue, pstr, rgFields[icol-1].precision)); break; default: bCompare=(!_tcsncmp(rgbValue, pstr, _tcslen(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); hdesc=NULL; // Global hdesc needs to be NULL or attempt to read freed mem } /*-----------------------------------------------------------------------*/ /* Function: GetSomeData */ /*-----------------------------------------------------------------------*/ VOID GetSomeData(HSTMT lhstmt, LPTSTR szTableName,BOOL fBindCol, FIELDINFO rgField) { RETCODE rc=SQL_SUCCESS; SDWORD cbValue=0; CHAR szQuery[XLARGEBUFF]=TEXT(""), szBuff[XLARGEBUFF]=TEXT(""); CHAR szErrMsg[MAX_STRING_SIZE]=TEXT(""), szDataItem[XLARGEBUFF]=TEXT(""); LPTSTR pch=NULL; pch = qtMakeData(0, 0,&rgField, szDataItem); sprintf(szQuery,szSELECTSTAR,szTableName); rc=SQLExecDirect(lhstmt,szQuery,SQL_NTS); // RETCHECK(SQL_SUCCESS,rc,szSQLEXECDIRECT); if (fBindCol) { rc = SQLBindCol(lhstmt, 1, SQL_C_CHAR, 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_CHAR,szBuff, sizeof(szBuff), NULL); // RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); } _tcscmp(szDataItem,szBuff); } /* GetSomeData() */ /*-----------------------------------------------------------------------*/ /* Function: SelectFromTable */ /*-----------------------------------------------------------------------*/ RETCODE SelectFromTable(QTSTRUCT *lpqt) { RETCODE rc=SQL_SUCCESS; CHAR szQuery[LARGEBUFF]; sprintf(szQuery,TEXT("select %s from %s"), //sprintf(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 */ /*-----------------------------------------------------------------------*/ RETCODE SelectFromTableFetch(QTSTRUCT *lpqt, CHAR* szColName) { RETCODE rc=SQL_SUCCESS; CHAR szQuery[LARGEBUFF]; sprintf(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 //----------------------------------------------------------------------- BOOL AllocHstmt() { BOOL fFailed=FALSE; RETCODE rc=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 //----------------------------------------------------------------------- BOOL AllocHdbc(HDBC *phdbc) { BOOL fFailed=FALSE; RETCODE rc=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 //----------------------------------------------------------------------- BOOL AllocHenv() { BOOL fFailed=FALSE; RETCODE rc=SQL_SUCCESS; rc = SQLAllocEnv(&henv); if (!RETCHECK(SQL_SUCCESS, rc,szSQLALLOCENV)) fFailed=TRUE; return(fFailed); } //AllocHenv() //----------------------------------------------------------------------- // Function: SetStatementAttributes //----------------------------------------------------------------------- BOOL SetStatementAttributes(UWORD fAttr, PTR rgbValue) { RETCODE rc=SQL_SUCCESS; CHAR szAPI[MEDBUFF]; BOOL fFailed=FALSE; if (Supported(SQL_API_SQLSETSTMTATTR)) { rc = SQLSetStmtAttr(hstmt,(SDWORD)fAttr,rgbValue,sizeof(UDWORD)); _tcscpy(szAPI,szSQLSETSTMTATTR); } else { rc = SQLSetStmtOption(hstmt,fAttr,(UDWORD)rgbValue); _tcscpy(szAPI,szSQLSETSTMTOPTION); } if (rc != SQL_SUCCESS) { if(!FindError(SQL_HANDLE_STMT,szHYC00)) RETCHECK(SQL_SUCCESS, rc,szAPI); fFailed=TRUE; } return(fFailed); } //SetStatementAttributes() //----------------------------------------------------------------------- // Function: SetConnectionAttributes //----------------------------------------------------------------------- BOOL SetConnectionAttributes(HDBC lhdbc,UWORD fAttr, UDWORD rgbValue) { RETCODE rc=SQL_SUCCESS; CHAR szAPI[MEDBUFF]; BOOL fFailed=FALSE; if (Supported(SQL_API_SQLSETCONNECTATTR)) { rc = SQLSetConnectAttr(lhdbc,(SDWORD)fAttr,(PTR)rgbValue,sizeof(UDWORD)); _tcscpy(szAPI,szSQLSETCONNECTATTR); } else { rc = SQLSetConnectOption(lhdbc,fAttr,rgbValue); _tcscpy(szAPI,szSQLSETCONNECTOPTION); } if (rc != SQL_SUCCESS) { if(!FindError(SQL_HANDLE_DBC,szHYC00)) RETCHECK(SQL_SUCCESS, rc,szAPI); fFailed=TRUE; } return(fFailed); } //SetConnectionAttributes() //----------------------------------------------------------------------- // Function: FreeStmt //----------------------------------------------------------------------- BOOL FreeStmt(UWORD fOption) { RETCODE rc=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 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 //----------------------------------------------------------------------- VOID 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 ClearErrorQueue() { CHAR szErrMsg[MAX_STRING_SIZE]; CHAR szState[6]; /* Eat up the SQL_SUCCESS_WITH_INFO error record */ while (RC_SUCCESSFUL(SQLError(NULL, hdbc,NULL, szState, NULL, szErrMsg, sizeof(szErrMsg)/sizeof(CHAR), NULL))) ; } //----------------------------------------------------------------------- // Function: Is3XDriver //----------------------------------------------------------------------- BOOL Is3XDriver(HDBC hdbc,QTSTRUCT *lpqt) { RETCODE rc=SQL_SUCCESS; LPTSTR pch=NULL; BOOL f3XDriver=FALSE; rc = SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, lpqt->buf, sizeof(lpqt->buf), 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 Connect(lpSERVERINFO lpSI,QTSTRUCT *lpqt) { RETCODE rc=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 */ sprintf(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_NOPROMPT); 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)) { _tcscpy(szHY009, TEXT("S1009")); _tcscpy(szHYC00, TEXT("S1C00")); } return(FALSE); ConnectErrorRet: return(TRUE); } //Connect() //----------------------------------------------------------------------- // Function: IgnoreType //----------------------------------------------------------------------- BOOL 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 (!_tcscmp(szType,TEXT("LONG RAW")) || !_tcscmp(szType,TEXT("LONG VARCHAR")) || !_tcscmp(szType,TEXT("LONG VARCHAR FOR BIT DATA"))) { fIgnore=TRUE; } //if (wSQLType != SQL_CHAR) // fIgnore=TRUE; return(fIgnore); } //IgnoreType() //----------------------------------------------------------------------- // Function: CheckConformanceLevel //----------------------------------------------------------------------- UWORD CheckConformanceLevel() { RETCODE rc=SQL_SUCCESS; UWORD fIndex=0; SWORD cb=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 TestConnectionOptions() { RETCODE rc=SQL_SUCCESS; SDWORD sdw, cbValue=0; BOOL fConnectOption=TRUE; CHAR szAPI[MEDBUFF]; HDBC lhdbc=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); _tcscpy(szAPI,szSQLGETCONNECTATTR); } else { rc = SQLGetConnectOption(lhdbc, SQL_LOGIN_TIMEOUT, &sdw); _tcscpy(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 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 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 CheckData(SWORD fHandleType,UWORD uwDescField, PTR rgbValue,LPTSTR szDataSourceName) { CHAR szBuff[MEDBUFF]=TEXT(""); LPTSTR pszExpState=szHY009; if (fHandleType == SQL_HANDLE_DESC) pszExpState=szHY091; switch(uwDescField) { case SQL_DIAG_RETURNCODE: { RETCODE rcRec=*(RETCODE *)rgbValue; if (rcRec!= SQL_ERROR) { sprintf(szBuff,TEXT("\t\t\tSQL_DIAG_RETURN_CODE\tReceived: %d\tExpected: %d"),rcRec,-1); } } break; case SQL_DIAG_SQLSTATE: { if (_tcscmp((LPTSTR)rgbValue,pszExpState)) { sprintf(szBuff,TEXT("\t\t\tSQL_DIAG_SQLSTATE\tReceived: %s\tExpected: %s"),(LPTSTR)rgbValue,pszExpState); } } break; case SQL_DIAG_CLASS_ORIGIN: { if (_tcscmp((LPTSTR)rgbValue,szISO)) sprintf(szBuff,TEXT("\t\t\tSQL_DIAG_CLASS_ORIGIN\tReceived: %s\tExpected: %s"),(LPTSTR)rgbValue,szISO); } break; case SQL_DIAG_SUBCLASS_ORIGIN: { if (_tcscmp((LPTSTR)rgbValue,szISO)) sprintf(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) sprintf(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 (_tcscmp((LPTSTR)rgbValue,szDataSourceName)) sprintf(szBuff,TEXT("\t\t\tSQL_DIAG_SERVER_NAME\tReceived: %s\tExpected: %s"),(LPTSTR)rgbValue,szDataSourceName); break; } } break; default: break; } if (*szBuff) DISPLAYERROR(szSQLGETDIAGFIELD,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 TestDiagRec() { SQLRETURN rcFunction, rc=SQL_SUCCESS; SWORD cbErrorMsg; SDWORD fNativeError; UWORD iHandle=0, iField=0, cHandles; SDWORD *pfNativeError = NULL; LPTSTR pchMessageText = NULL; CHAR szDataSourceName[MAX_STRING_SIZE] = TEXT(""); CHAR szState[SQL_SQLSTATE_SIZE+1]; CHAR szErrorMsg[SQL_MAX_MESSAGE_LENGTH]; CHAR szAPI[MEDBUFF]=TEXT(""); CHAR szBuff[MEDBUFF]=TEXT(""); LPTSTR pszExpState=szHY009; RETCODE rcExp=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, sizeof(szDataSourceName), 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) && _tcscmp(szState,pszExpState)) { sprintf(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 TestDiagField() { SQLRETURN rcFunction, rc=SQL_SUCCESS; SWORD cbValue=0; UWORD iHandle=0, iField=0, cHandles; CHAR szDataSourceName[MAX_STRING_SIZE] = TEXT(""); CHAR rgbValue[SQL_MAX_MESSAGE_LENGTH]; CHAR szAPI[MEDBUFF]=TEXT(""); CHAR szBuff[MEDBUFF]=TEXT(""); RETCODE rcExp=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, sizeof(szDataSourceName), 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, SQLCHAR * szAPI) { return; } //------------------------------------------------------------------------------ // Function: CompareAnsiUnicodeResults // Compares an ANSI result set to a Unicode result set //------------------------------------------------------------------------------ void CompareAnsiUnicodeResults(SQLHSTMT hstmtA, SQLHSTMT hstmtW, SQLCHAR * szAPI) { return; } /*------------------------------------------------------------------------------ / Function: TestMixedAnsiUnicode / Purpose: Call several of the Unicode functions mixed with ANSI functions / to verify functions succeed in the mixed case. /*----------------------------------------------------------------------------*/ void TestMixedAnsiUnicode(QTSTRUCT * lpqt) { return; } /* TestMixedAnsiUnicode() */ //----------------------------------------------------------------------- // Function: TestStmtOptions //----------------------------------------------------------------------- void TestStmtOptions() { UDWORD dwLen, udw; BOOL fConnectOption; RETCODE rc=SQL_SUCCESS; CHAR szAPI[MEDBUFF]; SDWORD cbValue=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); _tcscpy(szAPI,szSQLGETSTMTATTR); } else { rc = SQLGetStmtOption(hstmt, SQL_MAX_LENGTH, &dwLen); _tcscpy(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 SetTableName(QTSTRUCT *lpqt) { RETCODE rc=SQL_SUCCESS; UWORD cTableName; CHAR szTime[MEDBUFF]=TEXT(""), szTmpBuff[MEDBUFF], *pTime=NULL; _tstrtime(szTmpBuff); /* Remove colons */ pTime=_tcstok(szTmpBuff, TEXT(":")); while (pTime) { _tcscat(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, sizeof(lpqt->buf), NULL); if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); if(!(_tcscmp(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 GetTypeInfo(FIELDINFO *rgFields,QTSTRUCT *lpqt) { RETCODE rc=SQL_SUCCESS; UWORD cFieldName; SDWORD cMaxTypeSize, cMaxRowSize; UWORD i, cTypes=0; SDWORD sdw; LPTSTR pch=NULL; BOOL fAutoInc=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_CHAR, rgFields[i].szType, sizeof(rgFields[i].szType), &sdw); if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA)) goto TypeErrorRet; sprintf(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_CHAR, rgFields[i].szLength, sizeof(rgFields[i].szLength), &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_CHAR, rgFields[i].szPrefix, sizeof(rgFields[i].szPrefix), &sdw); if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA)) goto TypeErrorRet; /* suffix */ rc = SQLGetData(hstmt, 5, SQL_C_CHAR, rgFields[i].szSuffix, sizeof(rgFields[i].szSuffix), &sdw); if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA)) goto TypeErrorRet; /* create params */ rc = SQLGetData(hstmt, 6, SQL_C_CHAR, rgFields[i].szParams, sizeof(rgFields[i].szParams), &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 BuildCreateStmt(QTSTRUCT *lpqt,FIELDINFO *rgFields,UWORD cTypes) { RETCODE rc=SQL_SUCCESS; CHAR 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'); _tcscpy(lpqt->sz,TEXT("Create Table ")); _tcscat(lpqt->sz, lpqt->szTableName); _tcscat(lpqt->sz,TEXT(" (")); for(i = 0; i < cTypes; i++) { CHAR szParamType[50]; CHAR szNotNull[10]; *lpqt->szParam = TEXT('\0'); /* if SQLGetTypeInfo returned params they need to be used in the create statement */ if(rgFields[i].szParams == NULL || _tcslen(rgFields[i].szParams) == 0) *lpqt->szParam = TEXT('\0'); else if(_tcschr(rgFields[i].szParams, TEXT(',')) == NULL) sprintf(lpqt->szParam,TEXT("(%s)"), rgFields[i].szLength); else { _tcscpy(szNum, rgFields[i].szLength); sprintf(lpqt->szParam,TEXT("(%s, %d)"), rgFields[i].szLength, _ttoi(szNum) - SCALEDIFF); } _tcscpy(szParamType, rgFields[i].szType); if(pch = _tcschr((LPTSTR)szParamType, TEXT('('))) { *pch = TEXT('\0'); _tcscat(szParamType, lpqt->szParam); _tcscat(szParamType, (LPTSTR)_tcschr(rgFields[i].szType, TEXT(')')) + 1); } else { _tcscat(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)) _tcscpy(szNotNull,TEXT("NOT NULL")); else szNotNull[0] = TEXT('\0'); sprintf(&lpqt->sz[_tcslen(lpqt->sz)],TEXT(" %s %s %s ,"), rgFields[i].szFieldName, (LPTSTR)szParamType, (LPTSTR)szNotNull); } /* remove the last comma and space */ lpqt->sz[_tcslen(lpqt->sz) - 2] = TEXT('\0'); _tcscat(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 */ _tcscpy(lpqt->sz,TEXT("select ")); for(i = 0; i < cTypes; i ++) { if(i) _tcscat(lpqt->sz,TEXT(",")); _tcscat(lpqt->sz, rgFields[i].szFieldName); } _tcscat(lpqt->sz,TEXT(" from ")); _tcscat(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 BuildInsertStmt(QTSTRUCT *lpqt,FIELDINFO *rgFields,UWORD cTypes, DSTRUCT *lpd,SDWORD *cColsSelected,BOOL fBindParameter) { RETCODE rc; UWORD w; UWORD i; PTR ptr; UWORD ind; SDWORD sdw; LPTSTR pch=NULL; BOOL fColNames=TRUE, fLongData=FALSE; SDWORD *sdwArray = (SDWORD *)AllocateMemory(sizeof(SDWORD) * MAX_TYPES_SUPPORTED); _tcscpy(lpqt->szColNames,TEXT("\0")); _tcscpy(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) { _tcscpy(lpd[w].data, pch); lpd[w].cb = SQL_NTS; } else { _tcscpy(lpd[w].data,TEXT("")); lpd[w].cb = SQL_NULL_DATA; } if(fColNames) { /* the first time throught, the insert */ /* statement itself is created */ _tcscat(lpqt->szColNames, rgFields[ind].szFieldName); _tcscat(lpqt->szColNames,TEXT(", ")); _tcscat(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_CHAR, 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_CHAR, 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[_tcslen(lpqt->szColNames) - 2] = TEXT('\0'); lpqt->szValues[_tcslen(lpqt->szValues) - 2] = TEXT('\0'); sprintf(lpqt->sz,TEXT("insert into %s (%s) VALUES(%s)"), lpqt->szTableName, lpqt->szColNames, lpqt->szValues); //copy the insert statement, with the column names. //_ASSERTE(_tcslen(lpqt->sz) < MAX_STRING_SIZE); _tcscpy(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_CHAR, 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_CHAR, 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: SQLFreeStmt(hstmt, SQL_RESET_PARAMS); ReleaseMemory(sdwArray); return(TRUE); } //BuildInsertStmt() //----------------------------------------------------------------------- // Function: FullDisconnect //----------------------------------------------------------------------- void 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 DropTable(LPTSTR szTableName, BOOL fSilent) { CHAR szBuff[100]; RETCODE rc=SQL_ERROR; _tcscpy(szBuff,TEXT("drop table ")); _tcscat(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 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 BindAllColumns(QTSTRUCT *lpqt,FIELDINFO *rgFields,UWORD cTypes, DSTRUCT *lpd) { //----------------------------------------------------------------------- // Function: BindAllColumns UWORD i, w; RETCODE rc=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: case SQL_TYPE_DATE: rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, &lpd[i].date, IGNORED, &lpd[i].cb); break; case SQL_TIME: case SQL_TYPE_TIME: rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, &lpd[i].time, IGNORED, &lpd[i].cb); break; case SQL_TIMESTAMP: case SQL_TYPE_TIMESTAMP: rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT, &lpd[i].timestamp, IGNORED, &lpd[i].cb); break; case SQL_CHAR: case SQL_VARCHAR: case SQL_LONGVARCHAR: case SQL_NUMERIC: case SQL_DECIMAL: rc = SQLBindCol(hstmt, w, SQL_C_CHAR, lpd[i].data, MAX_STRING_SIZE*sizeof(SQLCHAR), &lpd[i].cb); break; 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 BindFetchColumns(QTSTRUCT *lpqt,FIELDINFO *rgFields,UWORD cTypes, DSTRUCT *lpdFetch) { UWORD i, w; RETCODE rc=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_CHAR, lpdFetch[i].data, sizeof(lpdFetch[i].data), &lpdFetch[i].cb); break; case SQL_CHAR: case SQL_VARCHAR: case SQL_NUMERIC: case SQL_DECIMAL: default: rc = SQLBindCol(hstmt, w, SQL_C_CHAR, lpdFetch[i].data, sizeof(lpdFetch[i].data), &lpdFetch[i].cb); break; } if(!RETCHECK(SQL_SUCCESS, rc, szSQLBINDCOL)) return(FALSE); } return(TRUE); } /*BindFetchColumns() */ //----------------------------------------------------------------------- // Function: TestMetaData //----------------------------------------------------------------------- void TestMetaData(lpSERVERINFO lpSI, QTSTRUCT *lpqt,FIELDINFO *rgFields,UWORD cTypes) { SWORD wNum; UWORD w; UWORD i; UDWORD dwLen; RETCODE rc=SQL_SUCCESS; SWORD wType; SWORD wNull; 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, sizeof(lpqt->buf)/sizeof(CHAR), NULL, &wType, &dwLen, &wNum, &wNull); RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBECOL); /* verify that column name returned is column name created */ if(0 != _tcsicmp(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 RetrieveData(QTSTRUCT *lpqt,FIELDINFO *rgFields, UWORD cTypes,DSTRUCT *lpd) { RETCODE rc=SQL_SUCCESS; UWORD ind, i; SDWORD nSame; LPTSTR pch=NULL; CHAR szNum[MAX_NUM_BUFFER]; /* used with _ttoi and itoa conversions */ CHAR *stopstring=NULL; double Num=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); _tcscpy(szNum, pch); nSame = _ttol(szNum) == lpd[i].sdword; break; case SQL_SMALLINT: if(lpd[i].cb != sizeof(SWORD)) DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); _tcscpy(szNum, pch); nSame = _ttoi(szNum) == lpd[i].sword; break; case SQL_FLOAT: case SQL_DOUBLE: if(lpd[i].cb != sizeof(SDOUBLE)) DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); _tcscpy(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); _tcscpy(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(SCHAR)) DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); _tcscpy(szNum, pch); nSame = (SCHAR)_ttoi(szNum) == (SCHAR)lpd[i].data[0]; break; case SQL_DECIMAL: case SQL_NUMERIC: if(lpd[i].cb > MAX_STRING_SIZE*sizeof(CHAR)) DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); // Chg _tcslen to strlen below pending spec decision if((lpd[i].cb / sizeof(CHAR)) > (UDWORD)_tcslen(lpd[i].data)) DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); { CHAR szNum2[MAX_NUM_BUFFER]; _tcscpy(szNum, pch); _tcscpy(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*sizeof(CHAR)) DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); if(lpd[i].cb / sizeof(SQLCHAR) > _tcslen(lpd[i].data)) DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); nSame = (SDWORD)_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 != (SWORD)_tcslen(pch)) DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); nSame = TRUE; /* not checking returned data for binary */ break; case SQL_CHAR: if(lpd[i].cb > MAX_STRING_SIZE*sizeof(CHAR) && rc == SQL_SUCCESS) DISPLAYERROR(szRETDATA,TEXT("incorrect return code for outlen")); if(((lpd[i].cb / sizeof(CHAR)) != (UDWORD)rgFields[i].precision) && rc == SQL_SUCCESS) DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN); nSame = !_tcsnccmp(lpd[i].data, pch, _tcslen(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 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 CreateParamQuery(QTSTRUCT *lpqt, FIELDINFO *rgFields,UWORD cTypes) { RETCODE rc=SQL_SUCCESS; UWORD i; LPTSTR pch=NULL; CHAR szQuery[MAX_QUERY_SIZE]; static SDWORD sdw = SQL_DATA_AT_EXEC; UWORD w, ind; sprintf(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: sprintf(&szQuery[_tcslen(szQuery)],TEXT("%s < ? + 1 and "), rgFields[i].szFieldName); break; default: sprintf(&szQuery[_tcslen(szQuery)],TEXT("%s = ? and "), rgFields[i].szFieldName); } if(!fBindParameter) { rc = SQLSetParam(hstmt, w, SQL_C_CHAR, 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_CHAR, 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[_tcslen(szQuery) - 5] = TEXT('\0'); } _tcscpy(lpqt->szParamQuery, szQuery); } //----------------------------------------------------------------------- // Function: TestSearchedQuery //----------------------------------------------------------------------- void TestSearchedQuery(QTSTRUCT *lpqt,FIELDINFO *rgFields, UWORD cTypes,DSTRUCT *lpd,BOOL fBindParameter) { RETCODE rc=SQL_SUCCESS; UWORD i; LPTSTR pch=NULL; SDWORD sdw; UWORD w; UDWORD udw; UWORD ind; sprintf(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: sprintf(&lpqt->sz[_tcslen(lpqt->sz)], TEXT("%s < ? + 1 and "), rgFields[i].szFieldName); break; default: sprintf(&lpqt->sz[_tcslen(lpqt->sz)], TEXT("%s = ? and "), rgFields[i].szFieldName); } if(!fBindParameter){ rc = SQLSetParam(hstmt, w, SQL_C_CHAR, 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_CHAR, 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[_tcslen(lpqt->sz) - 5] = TEXT('\0'); _tcscpy(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 = _tcslen(pch); rc = SQLPutData(hstmt, pch, (SDWORD)_tcslen(pch)*sizeof(SQLCHAR)); 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); FreeStmt(SQL_RESET_PARAMS); } //TestSearchedQuery() //----------------------------------------------------------------------- // Function: TestLargeQuery //----------------------------------------------------------------------- void TestLargeQuery(QTSTRUCT *lpqt,FIELDINFO *rgFields, UWORD cTypes,DSTRUCT *lpd) { RETCODE rc=SQL_SUCCESS; UWORD ind=0, i; LPTSTR pch=NULL; CHAR szQuery[2048]; /* > 1K query */ sprintf(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(_tcslen(szQuery) < 1024L) { int li=_tcslen(szQuery); switch(rgFields[i].wSQLType) { case SQL_REAL: case SQL_FLOAT: case SQL_DOUBLE: sprintf(&szQuery[_tcslen(szQuery)],TEXT("%s < %s + 1 and "), rgFields[i].szFieldName, pch); break; default: sprintf(&szQuery[_tcslen(szQuery)],TEXT("%s = %s%s%s and "), rgFields[i].szFieldName, rgFields[i].szPrefix, pch, rgFields[i].szSuffix); break; } } /* remove the final "and " */ szQuery[_tcslen(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 TestSQLTables(QTSTRUCT *lpqt) { RETCODE rc=SQL_SUCCESS; BOOL fFoundTable=FALSE; UWORD i; /* 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_CHAR, lpqt->sz, sizeof(lpqt->sz), 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 == _tcsicmp(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 TestSQLSpecialCols(QTSTRUCT *lpqt) { RETCODE rc=SQL_SUCCESS; UWORD i; rc = SQLSpecialColumns(hstmt, SQL_BEST_ROWID, NULL, 0, NULL, 0, lpqt->szTableName, (SWORD)(_tcslen(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 VerifyIndex(QTSTRUCT *lpqt,UWORD fIndex) { RETCODE rc=SQL_SUCCESS; BOOL fFoundTable=FALSE; UWORD i; SDWORD sdw; 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_CHAR, lpqt->sz, sizeof(lpqt->sz), &sdw); RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); if (_tcsicmp(lpqt->sz, lpqt->szTableName) == 0) { rc = SQLGetData(hstmt, 6, SQL_C_CHAR, lpqt->sz, sizeof(lpqt->sz), &sdw); RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); fFoundTable += 0 == _tcsicmp(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 TestSQLStatistics(QTSTRUCT *lpqt,FIELDINFO *rgFields, UWORD cTypes,DSTRUCT *lpd,UWORD fIndex) { RETCODE rc=SQL_SUCCESS; UWORD i; _tcscpy(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; _tcscpy(lpqt->buf, rgFields[i].szFieldName); sprintf(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 TestLikeQuery(QTSTRUCT *lpqt,FIELDINFO *rgFields, UWORD cTypes,DSTRUCT *lpd) { RETCODE rc=SQL_SUCCESS; UWORD i; SDWORD cbValue=0; for(i = 0; i < cTypes; i++) { if(rgFields[i].fSearchable == SQL_LIKE_ONLY || rgFields[i].fSearchable == SQL_SEARCHABLE) { _tcscpy(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 */ sprintf(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_CHAR, lpqt->sz, sizeof(lpqt->sz), &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 TestOJCap(QTSTRUCT *lpqt) { RETCODE rc=SQL_SUCCESS; UDWORD udw; 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) { sprintf(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, sizeof(lpqt->buf), 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 TestExtendedFetch(QTSTRUCT *lpqt, FIELDINFO *rgFields, UWORD cTypes) { RETCODE rc=SQL_SUCCESS; WORD fLevel2 = FALSE; DWORD dwLen=0; SWORD fSqlType; SDWORD cbValue=0; UWORD iTableCol,row,iCol,uwRowSetSize; CHAR szQuery[MAX_STRING_SIZE], szColName[SMALLBUFF]; CHAR* rgbValue = NULL; DSTRUCT* rgData = NULL; DSTRUCT* pDataBuf; BOOL fCol0Bound=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*sizeof(CHAR)))){ DISPLAYERROR(szSQLEXTENDEDFETCH,TEXT("Insufficient Memory Available")); ReleaseMemory(rgData); return; } /* Get column for "order by" clause: */ sprintf(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, 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; rowbuf, 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'); sprintf(lpqt->buf, TEXT("Returned Data: (%s)"), rgbValue); DISPLAYERROR(TEXT("ExtendedFetch"),lpqt->buf); // goto abortxfetch; } } } abortxfetch: FreeStmt(SQL_CLOSE); FreeStmt(SQL_UNBIND); if ( rgData ) ReleaseMemory(rgData); if ( rgbValue ) 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 TestQuickRebind(QTSTRUCT * lpqt, FIELDINFO *rgFields, UWORD cTypes, DSTRUCT *lpd) { RETCODE rc; UWORD row,iCol,iRowset,uwRowsetSize,iRowsetRow,iTableCol; UDWORD udwRowSize; SWORD fSqlType; SDWORD sdwOffset; DSTRUCT *rgData, *pZeroRow; DSTRUCT *pCurrentRowData; CHAR szQuery[MAX_STRING_SIZE], szColName[SMALLBUFF]; SDWORD cbValue; CHAR* rgbValue=NULL; BOOL fCol0Bound=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 * sizeof(SQLCHAR)))){ DISPLAYERROR(szSQLEXTENDEDFETCH,TEXT("Insufficient Memory Available")); goto abortQuikRebind; } ResetHstmt(&hstmt); /* Get column for "order by" clause: */ sprintf(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, 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; rowbuf, 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'); sprintf(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; iRowsetRowszTableName, 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 TestSQLBrowseConnect(lpSERVERINFO lpSI) { RETCODE rc=SQL_SUCCESS; UWORD cMaxConnections=0; CHAR szBCString[40]; CHAR szDSN[40]; HDBC hdbcb=NULL; SQLINTEGER sdwCP; AllocHdbc(&hdbcb); rc = SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, &cMaxConnections, sizeof(int), NULL); RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); rc = SQLGetEnvAttr(henv, SQL_ATTR_CONNECTION_POOLING, &sdwCP, SQL_IS_INTEGER, NULL); RETCHECK(SQL_SUCCESS, rc,szSQLGETENVATTR); if ( SQL_CP_OFF != sdwCP) { DISPLAYERROR(szSQLBROWSECONNECT, szBrowseNotSupported); return; } if(cMaxConnections != 1) { _tcscpy(szBCString,TEXT("DSN=")); _tcscat(szBCString, lpSI->szValidServer0); if(lpSI->szValidServer0[0] == 0) { rc = SQLGetInfo(hdbc, SQL_DATA_SOURCE_NAME, szDSN, sizeof(szDSN), NULL); _tcscat(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 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 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 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 TestSQLNativeSQL(QTSTRUCT *lpqt) { RETCODE rc=SQL_SUCCESS; CHAR szQuery[XLARGEBUFF]; sprintf(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 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 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 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 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 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 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 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 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 TestSQLSetScrollOptions() { RETCODE rc=SQL_SUCCESS; UWORD i, j; UDWORD fSupportedOpt; UDWORD fSupportedCon; CHAR szState[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 TestConnectAttr(HDBC hdbc,SDWORD fAttribute, UDWORD rgbValue,LPTSTR lpAttr,BOOL fReadOnlyAttr) { RETCODE rc=SQL_SUCCESS; CHAR szBuff[LARGEBUFF]=TEXT(""); UDWORD pvParam=0; RETCODE rcExp=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)) { sprintf(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 TestSQLSetConnectAttr() { RETCODE rc = SQL_SUCCESS; UDWORD pvParam; UWORD rgbValue; BOOL fSupportSetConnectAttr = TRUE; BOOL fSupportGetConnectAttr = 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 TestSQLSetStmtAttr() { RETCODE rc = SQL_SUCCESS, rc2= SQL_SUCCESS; UDWORD pvParam; UWORD rgbValue; BOOL fSupportSetStmtAttr = TRUE; BOOL fSupportGetStmtAttr = 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) { HENV henv0 = ptArg->henv; HDBC hdbc0 = ptArg->hdbc; HSTMT hstmt0 = NULL; //RETCODE rc=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 ThreadLoop(void *pArg) { THREAD_STRUCT *ptArg = (THREAD_STRUCT *)pArg; int i; RETCODE rc; 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) { } //end of TestThreading() //----------------------------------------------------------------------- // Function: CreateDescRecord //----------------------------------------------------------------------- SWORD CreateDescRecord(SQLHDESC hdesc, SQLHSTMT hstmt, UWORD uwDescType) { UDWORD cbColDef; SWORD swColCount; SQLRETURN rc; SWORD fType, fSQLType; SWORD ibScale; CHAR 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_CHAR, 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_CHAR; 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_CHAR, 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) { CHAR * pszAPI, szOp[10]; SQLSMALLINT fValidOp; // Descriptor types operation is valid for if (DESC_UPDATE_MODE_READ == swUpdateMode) { pszAPI=szSQLGETDESCFIELD; _tcscpy(szOp, TEXT("read")); fValidOp=rgDescInfo[iDescField].fGettable; } else { pszAPI=szSQLSETDESCFIELD; _tcscpy(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) { sprintf(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) { sprintf(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 { sprintf(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, CHAR * pszAPI) { SQLRETURN rc; SQLCHAR 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) { sprintf(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 = (_tcslen(pNewvalue)+1) * sizeof(CHAR); } 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 sprintf(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 = _tcslen((LPTSTR)DescBuf) * sizeof(SQLCHAR); // For string fields // Make sure cbValue and cbValue2 agree if (cbValue != cbValue2) { sprintf(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 : _tcslen((LPTSTR)rgDescInfo[iDescField].NewValue)*sizeof(CHAR)); 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 sprintf(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, CHAR * 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) { sprintf(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 sprintf(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; CHAR szName[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 { sprintf(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)/sizeof(CHAR), &cbName, &fType2, &fSubType2, &Length, &Precision, &Scale, &Nullable); sprintf(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 TestGetDescField(QTSTRUCT * lpqt) { SQLRETURN rc=SQL_SUCCESS; SQLUSMALLINT iDescType; SQLHDESC hdesc1=NULL, hdesc2=NULL; PTR rgbValue=NULL; SQLSMALLINT swDescRecCount, swExpRecCount; SQLINTEGER cbValue; CHAR szName[MAX_DESC_BUF]=TEXT(""); CHAR szQuery[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 sprintf(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) { sprintf(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 sprintf(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 TestSetDescField(QTSTRUCT * lpqt) { SQLRETURN rc=SQL_SUCCESS; SQLUSMALLINT iDescType; SQLHDESC hdesc1=NULL, hdesc2=NULL; PTR rgbValue=NULL; SQLSMALLINT swDescRecCount, swExpRecCount; SQLINTEGER cbValue; CHAR szName[MAX_DESC_BUF]=TEXT(""); CHAR szQuery[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 sprintf(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 TestGetDescRec(QTSTRUCT * lpqt) { SQLRETURN rc=SQL_SUCCESS; SQLUSMALLINT iDescType; SQLHDESC hdesc1=NULL, hdesc2=NULL; PTR rgbValue=NULL; SQLSMALLINT swDescRec, swDescRecCount, iRecord, cbName, fType, fSubType, Precision, Scale, Nullable, swExpRecCount; SQLINTEGER Length, cbValue; CHAR szName[MAX_DESC_BUF]=TEXT(""); CHAR szQuery[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, MAX_DESC_BUF, &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 sprintf(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) { sprintf(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 { sprintf(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 { sprintf(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 sprintf(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 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; CHAR szQuery[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 sprintf(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 sprintf(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 TestCopyDesc(QTSTRUCT * lpqt) { SQLRETURN rc=SQL_SUCCESS; SQLUSMALLINT iDescType; SQLSMALLINT swExpRecCount; SQLHDESC hdesc1=NULL, hdesc2=NULL; PTR rgbValue=NULL; CHAR szName[MAX_DESC_BUF]=TEXT(""); CHAR szQuery[XLARGEBUFF]=TEXT(""); ResetHstmt(&hstmt); // 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 { // Perform a select stmt sprintf(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); } } // Free descriptor handle if (hdesc) { rc = SQLFreeHandle(SQL_HANDLE_DESC, hdesc); RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE); } ResetHstmt(&hstmt); } } //TestCopyDesc() //----------------------------------------------------------------------- // Function: TestDescDefaults //----------------------------------------------------------------------- void 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 sprintf(buf,TEXT("Error in %s field %s default value"), DescTypes[iDescType].szDescName,rgDescInfo[iDescField].szDescFieldName); DISPLAYERROR(szSQLGETDESCFIELD, buf); } } } } } } } // TestDescDefaults //----------------------------------------------------------------------- // Function: TestUseDesc //----------------------------------------------------------------------- void TestUseDesc(QTSTRUCT * lpqt, FIELDINFO *rgFields) { LPTSTR pch=NULL; SDWORD crow=0; CHAR szQuery[XLARGEBUFF]=TEXT(""); SQLRETURN rc; UWORD row, icol, paramno; SWORD ccol; CHAR * 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 sprintf(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(CHAR)); 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, 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 sprintf(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, pcbValue++) { // Bind to next column rc = DescBindCol(hstmt, icol, SQL_C_CHAR, rgbValue, MAX_STRING_SIZE*sizeof(CHAR), pcbValue); // rc = SQLBindCol(hstmt, icol, SQL_C_CHAR, rgbValue, MAX_STRING_SIZE*sizeof(CHAR), 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, pcbValue++) { CompareWithExpected(rgbValue, pcbValue, row, icol, rgFields); } } else ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_NO_DATA, rc, szSQLFETCH); } // Close the cursor and retry using SQLFetchScroll rc=SQLFreeStmt(hstmt, SQL_CLOSE); RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT); // Make sure we have a rowset size of 1 rc=SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)1, SQL_IS_UINTEGER); ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_SUCCESS, rc, szSQLSETDESCFIELD); // Re-execute the query rc = SQLExecDirect(hstmt, szQuery, SQL_NTS); RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT); // Fetch all the rows and check the bound value with MakeAData for // each column for (row=1, rc=SQL_SUCCESS; rc == SQL_SUCCESS; row++) { rc=SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 1); // 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, pcbValue++) { CompareWithExpected(rgbValue, pcbValue, row, icol, rgFields); } } else ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_NO_DATA, rc, szSQLFETCHSCROLL); } } 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 TestEnvAttr() { SQLINTEGER sdwEnvAttr; SQLRETURN rc; HENV tshenv; BOOL fSetSupported = Supported(SQL_API_SQLSETENVATTR), fGetSupported = Supported(SQL_API_SQLGETENVATTR); LONG DEFAULT_ODBC_VERSION; //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); DEFAULT_ODBC_VERSION = SQL_OV_ODBC2; if (RC_SUCCESSFUL(rc) && (DEFAULT_ODBC_VERSION != sdwEnvAttr)) { // Default value wrong sprintf(buf, TEXT("Value was not %d!"), DEFAULT_ODBC_VERSION); DISPLAYERROR(szSQLGETENVATTR,buf); } rc = SQLFreeHandle(SQL_HANDLE_ENV,tshenv); RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE); } //TestEnvAttr() //----------------------------------------------------------------------- // Function: GetRowCnt // // Get the row count of the table lpqt->szTalbeName //----------------------------------------------------------------------- SWORD GetRowCnt(QTSTRUCT *lpqt) { SWORD sRowCnt; RETCODE rc; // free the statment handle for a fresh start FreeStmt(SQL_DROP); AllocHstmt(); //get row count for the table sprintf(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 InsertOneRow(QTSTRUCT *lpqt,FIELDINFO *rgFields,UWORD cTypes, DSTRUCT *lpd,UWORD cSeed,BOOL fFreeHstmt) { RETCODE rc; UWORD w; UWORD ind; LPTSTR pch=NULL; SQLHDESC hdesc; SQLSMALLINT fParamType = SQL_PARAM_INPUT; CHAR szDataItem[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) { _tcscpy(lpd[w].data, pch); lpd[w].cb = SQL_NTS; } else { _tcscpy(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_CHAR, 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_CHAR, 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 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 TestEndTran(QTSTRUCT *lpqt,FIELDINFO *rgFields,UWORD cTypes, DSTRUCT *lpd) { SWORD i; RETCODE rc; SWORD sTXN; SWORD sRowCnt_Pre; SWORD sRowCnt_Aft; SQLSMALLINT fHandleType[]={SQL_HANDLE_ENV, SQL_HANDLE_DBC}; SDWORD cbValue=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 TestBindParam(QTSTRUCT *lpqt,FIELDINFO *rgFields,UWORD cTypes, DSTRUCT *lpd) { RETCODE rc; SQLINTEGER cbValue = SQL_NTS; CHAR szDataItem[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_CHAR, 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 TestFetchScroll(QTSTRUCT *lpqt) { RETCODE rc=SQL_SUCCESS; CHAR szSave[MAX_QUERY_SIZE]; DWORD dwLen=0; SDWORD cbValue=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_CHAR, lpqt->sz, sizeof(lpqt->sz), &cbValue); RETCHECK(SQL_SUCCESS, rc, szSQLBINDCOL); rc = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 3); RETCHECK(SQL_SUCCESS, rc, szSQLFETCHSCROLL); _tcscpy(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 qtDisplayError(LPTSTR szFunction, LPTSTR buf, LPTSTR szFile, int iLine) { CHAR 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); sprintf(szTmp,TEXT("\t\t\t%s: %d"), szFile, iLine); szWrite(szTmp, TRUE); szWrite(TEXT("\t\t\t -------- "), TRUE); lpSI->failed++; return; } /*-----------------------------------------------------------------------*/ /* Function: qtMakeData */ /*-----------------------------------------------------------------------*/ LPTSTR qtMakeData(int row, int col,FIELDINFO *rgField, LPTSTR buf) { int i; CHAR szColNum[10]; CHAR tmpbuf[256]; if(rgField->fAutoUpdate) return NULL; if(rgField->nullable && (row==col)) { _tcscpy(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*sizeof(CHAR)) ) sprintf(buf,TEXT("%d"), 1); else sprintf(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 */ sprintf(buf,TEXT("-%d.%d"), row, row); else sprintf(buf,TEXT("%d.%d"), row, row); break; case SQL_BIT: if(row > 2) sprintf(buf,TEXT("%d"), 1); else sprintf(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 */ sprintf(buf,TEXT("-%d"), row); else sprintf(buf,TEXT("%d"), row); break; case SQL_TIME: case SQL_TYPE_TIME: sprintf(buf,TEXT("{t '01:%02d:%02d'}"), row % 60, row % 60); break; case SQL_DATE: case SQL_TYPE_DATE: sprintf(buf,TEXT("{d '1994-%02d-%02d'}"), (row % 12) + 1, (row % 30) + 1); break; case SQL_TIMESTAMP: case SQL_TYPE_TIMESTAMP: // precision <= 16 means the timestamp column doesn't have enough precision to hold seconds if ( rgField->precision > 16 ) sprintf(buf,TEXT("{ts '1994-%02d-%02d 01:%02d:%02d'}"), (row % 12) + 1, (row % 30) + 1, row % 60, row % 60); else sprintf(buf,TEXT("{ts '1994-%02d-%02d 01:%02d:%02d'}"), (row % 12) + 1, (row % 30) + 1, row % 60, 0); break; case SQL_GUID: _itot(row, szColNum, 10); _tcscpy(tmpbuf, szColNum); for (i=0; i<11; i++){ _tcscat(tmpbuf, szColNum); } sprintf(buf, TEXT("%.8s-%.4s-%.4s-%.4s-%.12s"), tmpbuf, tmpbuf, tmpbuf, tmpbuf, tmpbuf); break; } return buf; } /*-----------------------------------------------------------------------*/ /* Function: TestNumResCols */ /*-----------------------------------------------------------------------*/ VOID TestNumResCols(SDWORD cColsSelected,QTSTRUCT *lpqt) { RETCODE rc=SQL_SUCCESS; SWORD wNum; 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 TestCursorName(QTSTRUCT *lpqt) { RETCODE rc=SQL_SUCCESS; CHAR szCursorName[MEDBUFF]; SWORD cb=0; SelectFromTable(lpqt); /* the cursor name should be created by the driver since one was */ /* not specified */ rc = SQLGetCursorName(hstmt, szCursorName, sizeof(szCursorName)/sizeof(CHAR), &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 GetDMVersion() { RETCODE rc=SQL_SUCCESS; CHAR szNum[MAX_NUM_BUFFER]; rc = SQLGetInfo(hdbc, SQL_ODBC_VER, szNum, sizeof(szNum), NULL); RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO); return((UWORD)_ttoi(_tcstok(szNum,TEXT(".")))); } /* GetDMVersion() */ //----------------------------------------------------------------------- // Function: DisplayTestName //----------------------------------------------------------------------- VOID 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 AutoTestName(LPTSTR szName, UINT * cbTestCases) { static CHAR szTestName[] = TEXT("Another Quick Test"); _tcscpy(szName, szTestName); *cbTestCases = sizeof(iTestNames)/sizeof(LPTSTR); return TRUE; } //----------------------------------------------------------------------- // Function: AutoTestDesc // Purpose: Provides gator with a list of tests which can be run. //----------------------------------------------------------------------- BOOL AutoTestDesc(UWORD iTest, LPTSTR szName, LPTSTR szDesc) { UWORD len=0; if (iTest > (sizeof(iTestNames)/sizeof(LPTSTR))) return FALSE; if (szName) _tcscpy(szName,iTestNames[iTest-1]); if (szDesc) _tcscpy(szDesc,TEXT(" ")); return TRUE; } //----------------------------------------------------------------------- // Function: AutoTestFunc //----------------------------------------------------------------------- void AutoTestFunc(lpSERVERINFO pTestSource) { RETCODE rc; UWORD cTypes; UDWORD dwLen; UWORD fIndex; SDWORD cColsSelected; FIELDINFO *rgFields = (FIELDINFO *)AllocateMemory(sizeof(FIELDINFO) * MAX_TYPES_SUPPORTED); QTSTRUCT *lpqt = (QTSTRUCT *)AllocateMemory(sizeof (QTSTRUCT)); DSTRUCT *lpd = (DSTRUCT *)AllocateMemory(sizeof (DSTRUCT) * MAX_TYPES_SUPPORTED); UWORD uDMVer; SDWORD cbValue=0; CHAR szAPI[MEDBUFF]; UWORD i; CHAR szState[100]=TEXT(""), szErrMsg[XLARGEBUFF]=TEXT(""); lpSI = pTestSource; lpSI->failed = 0; henv = NULL; hdbc = NULL; hstmt = NULL; hdesc = NULL; if(lpSI->szValidServer0[0]) { if (Connect(lpSI,lpqt)) goto ErrorRet; } else { henv = lpSI->henv; hdbc = lpSI->hdbc; rc = SQLSetConnectOption(hdbc,SQL_ODBC_CURSORS,dwLen); _tcscpy(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; }