home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / odbc / quiktest / quiktest.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-03  |  219.7 KB  |  7,294 lines

  1. //---------------------------------------------------------------------------------------
  2. //
  3. // PROGRAM: quiktest.c
  4. //        This code is furnished on an as-is basis as part of the ODBC SDK and is
  5. //        intended for example purposes only.
  6. //
  7. //  PURPOSE: This is a Quick Test of the basic functionality of an ODBC driver.
  8. //
  9. //  FUNCTIONS:
  10. //         QuickTest() - performs the quick test focusing on basic functionalities.
  11. //
  12. //--------------------------------------------------------------------------------------------
  13. #pragma warning (disable : 4703)
  14.  
  15. #define QUIKTEST
  16.  
  17. #include "autotest.h"
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <malloc.h>
  21. #include <wchar.h>
  22. #include <tchar.h>
  23. #include <time.h>
  24. // #include <crtdbg.h>
  25. #include "sql.h"
  26. #include "sqlext.h"
  27. #include "quiktest.h"
  28.  
  29. //--------------------------------------------------------------------------------------
  30. //      static
  31. //--------------------------------------------------------------------------------------
  32. static TCHAR  vszFile[]                = TEXT(__FILE__);
  33.  
  34. static LPTSTR sz07009                    = TEXT("07009");
  35. static LPTSTR szIM001                    = TEXT("IM001");
  36. static LPTSTR szHYC00                    = TEXT("HYC00");
  37. static LPTSTR szHY009                    = TEXT("HY009");
  38. static LPTSTR szHY091                    = TEXT("HY091");
  39. static LPTSTR szHY092                    = TEXT("HY092");
  40. static LPTSTR szISO                        = TEXT("ISO 9075");
  41. static LPTSTR szODBC30                    = TEXT("ODBC 3.0");
  42. static LPTSTR szNotSupported            = TEXT("did not return Not supported message");
  43. static LPTSTR szSQLSETCONNECTATTR    = TEXT("SQLSetConnectAttr");
  44. static LPTSTR szSQLGETCONNECTATTR    = TEXT("SQLGetConnecTAttr");
  45. static LPTSTR szSQLGETINFO                = TEXT("SQLGetInfo");
  46. static LPTSTR szSQLGETTYPEINFO        = TEXT("SQLGetTypeInfo");
  47. static LPTSTR szSQLALLOCHANDLE        = TEXT("SQLAllocHandle");
  48. static LPTSTR szSQLALLOCSTMT            = TEXT("SQLAllocStmt");
  49. static LPTSTR szSQLALLOCCONNECT        = TEXT("SQLAllocConnect");
  50. static LPTSTR szSQLALLOCENV            = TEXT("SQLAllocEnv");
  51. static LPTSTR szSQLSETSTMTATTR        = TEXT("SQLSetStmtAttr");
  52. static LPTSTR szSQLGETSTMTATTR        = TEXT("SQLGetStmtAttr");
  53. static LPTSTR szSQLSETSTMTOPTION        = TEXT("SQLSetStmtOption");
  54. static LPTSTR szSQLGETSTMTOPTION        = TEXT("SQLGetStmtOption");
  55. static LPTSTR szSQLSETCONNECTOPTION    = TEXT("SQLSetConnectOption");
  56. static LPTSTR szSQLGETCONNECTOPTION    = TEXT("SQLGetConnectOption");
  57. static LPTSTR szSQLFETCH                = TEXT("SQLFetch");
  58. static LPTSTR szSQLBINDCOL                = TEXT("SQLBindCol");
  59. static LPTSTR szSQLFOREIGNKEYS        = TEXT("SQLForeignkeys");
  60. static LPTSTR szSQLFREEHANDLE            = TEXT("SQLFreeHandle");
  61. static LPTSTR szSQLFREECONNECT        = TEXT("SQLFreeConnect");
  62. static LPTSTR szSQLFREEENV                = TEXT("SQLFreeEnv");
  63. static LPTSTR szSQLGETDESCREC            = TEXT("SQLGetDescRec");
  64. static LPTSTR szSQLSETDESCREC            = TEXT("SQLSetDescRec");
  65. static LPTSTR szSQLGETDESCFIELD        = TEXT("SQLGetDescField");
  66. static LPTSTR szSQLSETDESCFIELD        = TEXT("SQLSetDescField");
  67. static LPTSTR szSQLCOPYDESC            = TEXT("SQLCopyDesc");
  68. static LPTSTR szSQLSETENVATTR            = TEXT("SQLSetEnvAttr");
  69. static LPTSTR szSQLGETENVATTR            = TEXT("SQLGetEnvAttr");
  70. static LPTSTR szSQLFREESTMT            = TEXT("SQLFreeStmt");
  71. static LPTSTR szSQLENDTRAN                = TEXT("SQLEndTran");
  72. static LPTSTR szSQLGETCURSORNAME        = TEXT("SQLGetCursorName");
  73. static LPTSTR szSQLEXECDIRECT            = TEXT("SQLExecDirect");
  74. static LPTSTR szSQLPUTDATA                = TEXT("SQLPutData");
  75. static LPTSTR szSQLPARAMDATA            = TEXT("SQLParamData");
  76. static LPTSTR szSQLROWCOUNT            = TEXT("SQLRowCount");
  77. static LPTSTR szSQLSETPARAM            = TEXT("SQLSetParam");
  78. static LPTSTR szSQLBINDPARAMETER        = TEXT("SQLBindParameter");
  79. static LPTSTR szSQLBINDPARAM            = TEXT("SQLBindParam");
  80. static LPTSTR szSQLPREPARE                = TEXT("SQLPrepare");
  81. static LPTSTR szSQLEXECUTE                = TEXT("SQLExecute");
  82. static LPTSTR szSQLCOLATTRIBUTES        = TEXT("SQLColAttributes");
  83. static LPTSTR szSQLGETDATA                = TEXT("SQLGetData");
  84. static LPTSTR szSQLCOLUMNS                = TEXT("SQLColumns");
  85. static LPTSTR szSQLGETFUNCTIONS        = TEXT("SQLGetFunctions");                  
  86. static LPTSTR szSQLDRIVERCONNECT        = TEXT("SQLDriverConnect");
  87. static LPTSTR szSQLDISCONNECT            = TEXT("SQLDisconnect");
  88. static LPTSTR szSQLCONNECT                = TEXT("SQLConnect");
  89. static LPTSTR szSQLCANCEL                = TEXT("SQLCancel");
  90. static LPTSTR szSQLDESCRIBECOL        = TEXT("SQLDescribeCol");
  91. static LPTSTR szSQLTABLES                = TEXT("SQLTables");
  92. static LPTSTR szSQLSPECIALCOLUMNS    = TEXT("SQLSpecialColumns");
  93. static LPTSTR szSQLDESCRIBEPARAM        = TEXT("SQLDescribeParam");
  94. static LPTSTR szSQLNUMPARAMS            = TEXT("SQLNumParams");
  95. static LPTSTR szSQLPARAMOPTIONS        = TEXT("SQLParamOptions");
  96. static LPTSTR szSQLPRIMARYKEYS        = TEXT("SQLPrimaryKeys");
  97. static LPTSTR szSQLEXTENDEDFETCH        = TEXT("SQLExtendedFetch");
  98. static LPTSTR szSELECTSTAR                = TEXT("select * from %s");
  99. static LPTSTR szQUICKREBIND            = TEXT("Quick Rebind");
  100. static LPTSTR szSQLBROWSECONNECT        = TEXT("SQLBrowseConnect");
  101. static LPTSTR szBLANKLINE                = TEXT(" ");
  102. static LPTSTR szTAB                        = TEXT("\t");
  103. static LPTSTR szSQLNUMRESULTCOLS        = TEXT("SQLNumResultCols");
  104. static LPTSTR szSQLSETSCROLLOPTIONS    = TEXT("SQLSetScrollOptions");
  105. static LPTSTR szSQLFETCHSCROLL        = TEXT("SQLFetchScroll");
  106. static LPTSTR szSQLSTATISTICS            = TEXT("SQLStatistics");
  107. static LPTSTR szSQLCLOSECURSOR        = TEXT("SQLCloseCursor");
  108. static LPTSTR szSQLGETDIAGREC            = TEXT("SQLGetDiagRec");
  109. static LPTSTR szSQLGETDIAGFIELD        = TEXT("SQLGetDiagField");
  110. static LPTSTR szRETDATA                    = TEXT("returned data");
  111. static LPTSTR szINCORRECTOUTLEN        = TEXT("incorrect outlen");
  112. static LPTSTR szSQLNATIVESQL            = TEXT("SQLNativeSql");
  113. static LPTSTR szSQLNATIVESQLW            = TEXT("SQLNativeSqlW");
  114. static LPTSTR szSQLCONNECTW            = TEXT("SQLConnectW");
  115. static LPTSTR szSQLTABLESA                = TEXT("SQLTablesA");
  116. static LPTSTR szSQLTABLESW                = TEXT("SQLTablesW");
  117. static LPTSTR szSQLCOLUMNSA            = TEXT("SQLColumnsA");
  118. static LPTSTR szSQLCOLUMNSW            = TEXT("SQLColumnsW");
  119. static LPTSTR szSQLEXECDIRECTA        = TEXT("SQLExecDirectA");
  120. static LPTSTR szSQLEXECDIRECTW        = TEXT("SQLExecDirectW");
  121.  
  122. LPTSTR iTestNames[]={
  123.     TEXT("Test Connection Options"),
  124.     TEXT("Test Statement Options"),
  125.     TEXT("Test SQLGetCursorName"),
  126.     TEXT("Test Data"),
  127.     TEXT("Test SQLNumResultCols"),
  128.     TEXT("Test Meta-Data"),
  129.     TEXT("Test Searched Query"),
  130.     TEXT("Test Large Query"),
  131.     TEXT("Test SQLTables"),
  132.     TEXT("Test SQLStatistics"),
  133.     TEXT("Test SQLSpecialColumns"),
  134.     TEXT("Test 'Like' Query"),
  135.     TEXT("Test SQLForeignKeys"),
  136.     TEXT("Test SQLBrowseConnect"),
  137.     TEXT("Test SQLDataSources"),
  138.     TEXT("Test SQLDrivers"),
  139.     TEXT("Test SQLMoreResults"),
  140.     TEXT("Test SQLNativeSQL"),
  141.     TEXT("Test SQLDescribeParam"),
  142.     TEXT("Test SQLNumParams"),
  143.     TEXT("Test SQLParamOptions"),
  144.     TEXT("Test SQLPrimaryKeys"),
  145.     TEXT("Test SQLProcedures"),
  146.     TEXT("Test SQLTablePrivileges"),
  147.     TEXT("Test SQLColumnPrivileges"),
  148.     TEXT("Test SQLSetScrollOptions"),
  149.     TEXT("Test SQLExtendedFetch"),
  150.     TEXT("Test SQL_OJ_CAPABILITIES"),
  151.     TEXT("Test SQLSetConnectAttr"),
  152.     TEXT("Test SQLSetStmtAttr"),
  153.     TEXT("Test Threading"),
  154.     TEXT("Test GetDescField"),
  155.     TEXT("Test SetDescField"),
  156.     TEXT("Test GetDescRec"),
  157.     TEXT("Test SetDescRec"),
  158.     TEXT("Test CopyDesc"),
  159.     TEXT("Test Descriptor Defaults"),
  160.     TEXT("Test Usage of Descriptor"),
  161.     TEXT("Test Environment Attributes"),
  162.     TEXT("Test SQLEndTran"),
  163.     TEXT("Test SQLBindParam"),
  164.     TEXT("Test Quick Rebind"),
  165.     TEXT("Test SQLFetchScroll"),
  166.     TEXT("Test GetDiagRec"),
  167.     TEXT("Test GetDiagField"),
  168.     TEXT("Test MixedAnsiUnicode")
  169. };
  170.  
  171.  
  172. typedef struct tagHANDLES
  173. {
  174.     SWORD            fHandleType;
  175.     SQLHANDLE    hHandle;
  176.  
  177. } HANDLES, *lpHANDLES;
  178.  
  179. SUPPORTOPTINFO OptionList[] = {SQL_SO_FORWARD_ONLY, SQL_SCROLL_FORWARD_ONLY,
  180.                                     SQL_SO_KEYSET_DRIVEN, SQL_SCROLL_KEYSET_DRIVEN,
  181.                                     SQL_SO_DYNAMIC, SQL_SCROLL_DYNAMIC};
  182.  
  183. SUPPORTCONCURINFO ConcurList[] = {SQL_SCCO_READ_ONLY, SQL_CONCUR_READ_ONLY,
  184.                                     SQL_SCCO_LOCK, SQL_CONCUR_LOCK,
  185.                                     SQL_SCCO_OPT_TIMESTAMP, SQL_CONCUR_TIMESTAMP,
  186.                                     SQL_SCCO_OPT_VALUES, SQL_CONCUR_VALUES};
  187.  
  188.  
  189. /*--------------------------------------------------------------------------------------*/
  190. /*     globals                                                                                                         */
  191. /*--------------------------------------------------------------------------------------*/
  192. lpSERVERINFO    lpSI = NULL;
  193. UWORD                fBindParameter=FALSE,
  194.                     fDiagRecSupported=FALSE,
  195.                     fDiagFieldSupported=FALSE,
  196.                     uDriverODBCVer=0;
  197. UWORD                guwRowCount=0;    // Count of rows in the automaketable
  198.   
  199. /* these are globals so that the error functions can access them without
  200.         needing to have them passed to every error check */
  201. static HENV            henv=SQL_NULL_HENV;
  202. static HDBC            hdbc=SQL_NULL_HDBC;
  203. static HSTMT           hstmt=SQL_NULL_HSTMT;
  204. static SQLHDESC        hdesc=SQL_NULL_HDESC;
  205.  
  206.  
  207.  
  208. //globals for test descriptors
  209. TIMESTAMP_STRUCT tsval= {1955, 12, 31, 23, 59, 59, 999};
  210. SQLINTEGER cbtsval=sizeof(TIMESTAMP_STRUCT);
  211. SQLINTEGER cbValueMax, cbValue, swBindOffset=128;
  212. SQLUINTEGER RowsProcessed;
  213. SQLSMALLINT DescBuf[MAX_DESC_BUF]; 
  214. SQLUSMALLINT StatusArray[STATUS_ARRAY_SIZE];
  215. SQLTCHAR buf[MAX_STRING_SIZE];
  216. SQLTCHAR szParamName[MAX_STRING_SIZE]=TEXT("Parameter Name");
  217.  
  218. struct tagDescType {
  219.     SQLUSMALLINT    uwDescType;
  220.     SQLUSMALLINT    uwTypeMask;
  221.     TCHAR szDescName[4];
  222. } DescTypes[] = {
  223.     SQL_ATTR_APP_ROW_DESC,        DESC_ARD,    TEXT("ARD"),
  224.     SQL_ATTR_APP_PARAM_DESC,    DESC_APD,    TEXT("APD"),
  225.     SQL_ATTR_IMP_ROW_DESC,        DESC_IRD,    TEXT("IRD"),
  226.     SQL_ATTR_IMP_PARAM_DESC,    DESC_IPD,    TEXT("IPD")
  227. };
  228.  
  229. struct tagDescInfo {
  230.     SQLSMALLINT uwDescField;
  231.     LPTSTR szDescFieldName;
  232.     BOOL fHeader;
  233.     SQLSMALLINT fGettable;    // Can be retrieved for given descriptor types
  234.     SQLSMALLINT fSettable;    // Can be set for given descriptor types
  235.     SQLSMALLINT fDefault;    // Has a default value for the descriptor types
  236.     SQLINTEGER NewValue;
  237.     SQLINTEGER DefaultVal;
  238.     SQLSMALLINT cbValue;
  239.     SQLINTEGER size;
  240. } rgDescInfo[] =    {
  241.     // Test expects all header fields to be listed first.  The TYPE field must be the first record field listed.
  242.     // size should be set to 0 for string fields, since we don't know up front what to set it to
  243.     // Field ID                                Field Name                                            Header    Gettable            Settable        fDefault        New Value                            Default Value            Data Size                    Data Type
  244.  
  245.     //Header fields
  246.     SQL_DESC_COUNT,                        TEXT("SQL_DESC_COUNT"),                        TRUE,    DESC_ALL,        DESC_MOST,    DESC_MOST,    1,                                0,                        sizeof(SQLSMALLINT),    SQL_IS_SMALLINT,
  247.     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,
  248.     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,
  249.     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,
  250.     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,
  251.     SQL_DESC_BIND_TYPE,                    TEXT("SQL_DESC_BIND_TYPE"),                    TRUE,    DESC_AD,        DESC_AD,    DESC_AD,    BIND_SIZE,                        0,                        sizeof(SQLINTEGER),        SQL_IS_INTEGER,
  252. //    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,
  253. //    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,
  254.     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,
  255.  
  256.     // Record fields
  257.     SQL_DESC_TYPE,                        TEXT("SQL_DESC_TYPE"),                         FALSE,    DESC_ALL,        DESC_MOST,    DESC_AD,    SQL_DATETIME,                    SQL_C_DEFAULT,            sizeof(SQLSMALLINT),    SQL_IS_SMALLINT,
  258.     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,
  259.     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,
  260.     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,
  261. //    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,
  262.     SQL_DESC_BASE_COLUMN_NAME,            TEXT("SQL_DESC_BASE_COLUMN_NAME"),            FALSE,    DESC_IRD,        DESC_NONE,    DESC_NONE,    (SQLINTEGER)szParamName,        0,                        sizeof(SQLCHAR),        0,
  263.     SQL_DESC_CASE_SENSITIVE,            TEXT("SQL_DESC_CASE_SENSITIVE"),            FALSE,    DESC_ID,        DESC_NONE,    DESC_NONE,    0,                                0,                        sizeof(SQLINTEGER),        SQL_IS_INTEGER,
  264.     SQL_DESC_CATALOG_NAME,                TEXT("SQL_DESC_CATALOG_NAME"),                FALSE,    DESC_IRD,        DESC_NONE,    DESC_NONE,    (SQLINTEGER)szParamName,        0,                        sizeof(SQLCHAR),        0,
  265.     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,
  266.     SQL_DESC_DISPLAY_SIZE,                TEXT("SQL_DESC_DISPLAY_SIZE"),                FALSE,    DESC_IRD,        DESC_NONE,     DESC_NONE,    0,                                0,                        sizeof(SQLINTEGER),        SQL_IS_INTEGER,
  267.     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,
  268.     SQL_DESC_LABEL,                        TEXT("SQL_DESC_LABEL"),                        FALSE,    DESC_IRD,        DESC_NONE,    DESC_NONE,    (SQLINTEGER)szParamName,        0,                        sizeof(SQLCHAR),        0,
  269.     SQL_DESC_LENGTH,                    TEXT("SQL_DESC_LENGTH"),                    FALSE,    DESC_ALL,        DESC_MOST,    DESC_NONE,    23,                                0,                        sizeof(SQLUINTEGER),    SQL_IS_UINTEGER,
  270.     SQL_DESC_LITERAL_PREFIX,            TEXT("SQL_DESC_LITERAL_PREFIX"),            FALSE,    DESC_IRD,        DESC_NONE,    DESC_NONE,    (SQLINTEGER)szParamName,        0,                        sizeof(SQLCHAR),        0,
  271.     SQL_DESC_LITERAL_SUFFIX,            TEXT("SQL_DESC_LITERAL_SUFFIX"),            FALSE,    DESC_IRD,        DESC_NONE,    DESC_NONE,    (SQLINTEGER)szParamName,        0,                        sizeof(SQLCHAR),        0,
  272.     SQL_DESC_LOCAL_TYPE_NAME,            TEXT("SQL_DESC_LOCAL_TYPE_NAME"),            FALSE,    DESC_IRD,        DESC_NONE,    DESC_NONE,    (SQLINTEGER)szParamName,        0,                        sizeof(SQLCHAR),        0,
  273.     SQL_DESC_NAME,                        TEXT("SQL_DESC_NAME"),                        FALSE,    DESC_ID,        DESC_IPD,    DESC_NONE,    (SQLINTEGER)szParamName,        0,                        sizeof(SQLCHAR),        0,
  274.     SQL_DESC_NULLABLE,                    TEXT("SQL_DESC_NULLABLE"),                    FALSE,    DESC_ID,        DESC_NONE,    DESC_NONE,    0,                                0,                        sizeof(SQLSMALLINT),    SQL_IS_SMALLINT,
  275.     SQL_DESC_OCTET_LENGTH,                TEXT("SQL_DESC_OCTET_LENGTH"),                FALSE,    DESC_ALL,        DESC_MOST,    DESC_NONE,    sizeof(tsval),                    0,                        sizeof(SQLINTEGER),        SQL_IS_INTEGER,
  276.     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,
  277.     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,
  278.     SQL_DESC_PRECISION,                    TEXT("SQL_DESC_PRECISION"),                    FALSE,    DESC_ALL,        DESC_MOST,    DESC_NONE,    23,                                0,                        sizeof(SQLSMALLINT),    SQL_IS_SMALLINT,
  279.     SQL_DESC_SCALE,                        TEXT("SQL_DESC_SCALE"),                        FALSE,    DESC_ALL,        DESC_MOST,    DESC_NONE,    3,                                0,                        sizeof(SQLSMALLINT),    SQL_IS_SMALLINT,
  280.     SQL_DESC_SCHEMA_NAME,                TEXT("SQL_DESC_SCHEMA_NAME"),                FALSE,    DESC_IRD,        DESC_NONE,    DESC_NONE,    (SQLINTEGER)szParamName,        0,                        sizeof(SQLCHAR),        0,
  281.     SQL_DESC_SEARCHABLE,                TEXT("SQL_DESC_SEARCHABLE"),                FALSE,    DESC_IRD,        DESC_NONE,    DESC_NONE,    0,                                0,                        sizeof(SQLSMALLINT),    SQL_IS_SMALLINT,
  282.     SQL_DESC_TABLE_NAME,                TEXT("SQL_DESC_TABLE_NAME"),                FALSE,    DESC_IRD,        DESC_NONE,    DESC_NONE,    (SQLINTEGER)szParamName,        0,                        sizeof(SQLCHAR),        0,
  283.     SQL_DESC_TYPE_NAME,                    TEXT("SQL_DESC_TYPE_NAME"),                    FALSE,    DESC_ID,        DESC_NONE,    DESC_NONE,    (SQLINTEGER)szParamName,        0,                        sizeof(SQLCHAR),        0,
  284.     SQL_DESC_UNSIGNED,                    TEXT("SQL_DESC_UNSIGNED"),                    FALSE,    DESC_ID,        DESC_NONE,    DESC_NONE,    0,                                0,                        sizeof(SQLSMALLINT),    SQL_IS_SMALLINT,
  285.     SQL_DESC_UPDATABLE,                    TEXT("SQL_DESC_UPDATABLE"),                    FALSE,    DESC_IRD,        DESC_NONE,    DESC_NONE,    0,                                0,                        sizeof(SQLSMALLINT),    SQL_IS_SMALLINT,
  286.     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,
  287.     SQL_DESC_UNNAMED,                    TEXT("SQL_DESC_UNNAMED"),                    FALSE,    DESC_ID,        DESC_IPD,    DESC_NONE,    SQL_UNNAMED,                    SQL_NAMED,                sizeof(SQLSMALLINT),    SQL_IS_SMALLINT,
  288.     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
  289.  };
  290.  
  291. struct tagDIAGINFO {
  292.     SQLSMALLINT uwDescField;
  293.     LPTSTR szDescFieldName;
  294.     SWORD irecRecNumber;
  295. } rgDiagInfo[] =    {
  296. //    SQL_DIAG_CURSOR_ROW_COUNT,            TEXT("SQL_DIAG_CURSOR_ROW_COUNT"),            0,
  297. //    SQL_DIAG_DYNAMIC_FUNCTION,            TEXT("SQL_DIAG_DYNAMIC_FUNCTION"),            0,
  298. //    SQL_DIAG_DYNAMIC_FUNCTION_CODE,    TEXT("SQL_DIAG_DYNAMIC_FUNCTION_CODE"),    0,
  299.     SQL_DIAG_NUMBER,                        TEXT("SQL_DIAG_NUMBER"),                        0,
  300.     SQL_DIAG_RETURNCODE,                    TEXT("SQL_DIAG_RETURNCODE"),                    0,
  301. //    SQL_DIAG_ROW_NUMBER,                    TEXT("SQL_DIAG_ROW_NUMBER"),                    0,
  302. //    SQL_DIAG_COLUMN_NUMBER,                TEXT("SQL_DIAG_COLUMN_NUMBER"),                1,
  303. //    SQL_DIAG_ROW_COUNT,                    TEXT("SQL_DIAG_ROW_COUNT"),                    0,
  304.     SQL_DIAG_SQLSTATE,                    TEXT("SQL_DIAG_SQLSTATE"),                        1,
  305.     SQL_DIAG_NATIVE,                        TEXT("SQL_DIAG_NATIVE"),                        1,
  306.     SQL_DIAG_MESSAGE_TEXT,                TEXT("SQL_DIAG_MESSAGE_TEXT"),                1,
  307.     SQL_DIAG_CLASS_ORIGIN,                TEXT("SQL_DIAG_CLASS_ORIGIN"),                1,
  308.     SQL_DIAG_SUBCLASS_ORIGIN,            TEXT("SQL_DIAG_SUBCLASS_ORIGIN"),            1,
  309. //    SQL_DIAG_CONNECTION_NAME,            TEXT("SQL_DIAG_CONNECTION_NAME"),            1,
  310.     SQL_DIAG_SERVER_NAME,                TEXT("SQL_DIAG_SERVER_NAME"),                    1,
  311. };
  312.  
  313. BOOL    g_f3XDriver=FALSE;
  314.  
  315. //the insert statement buffer    to hold the insert statement
  316. TCHAR szInsertStmt[MAX_STRING_SIZE];
  317.  
  318. //-----------------------------------------------------------------------
  319. //      Function:               Supported
  320. //-----------------------------------------------------------------------
  321.  
  322. _inline UWORD  PASCAL Supported(UWORD uwSQLFunc)
  323. {
  324.     UWORD        fLevel2=FALSE;
  325.     RETCODE    rc=SQL_SUCCESS;
  326.  
  327.     rc = SQLGetFunctions(hdbc, uwSQLFunc,&fLevel2);
  328.     RETCHECK(SQL_SUCCESS, rc,szSQLGETFUNCTIONS);
  329.  
  330.     return(fLevel2);
  331.  
  332. } //Supported()
  333.  
  334.  
  335. /*------------------------------------------------------------------------------
  336.  *    Function:    CheckDataResults - To check data returned by Fetch calls 
  337.  *    Checks data at (row, col) in result set against (row, col) in table
  338.  * ----------------------------------------------------------------------------*/
  339. BOOL CheckDataResults(SWORD row, SWORD iTableCol, FIELDINFO*  pField, DSTRUCT* pDataStr,
  340.                              SDWORD cbValue, TCHAR* rgbValue)
  341. {
  342.     if((pField ->nullable)&& (cbValue<1))
  343.     {
  344.         if(cbValue == SQL_NULL_DATA && pDataStr[iTableCol].cb == SQL_NULL_DATA)
  345.             return TRUE;
  346.         return FALSE;
  347.     }
  348.  
  349.     return CmpODBCtoCHAR(pDataStr, rgbValue, pField->wSQLType, iTableCol);
  350. }
  351.  
  352.  
  353. /*------------------------------------------------------------------------------
  354. /    Function:    BinToHex
  355. /    Purpose:    Render a buffer contents as a hexidecimal string.
  356. /*----------------------------------------------------------------------------*/
  357.  
  358. void PASCAL BinToHex(PTR rgbValue, SWORD cbValue, LPTSTR szHexString)
  359. {
  360.     UWORD ib;
  361.     LPTSTR pch;
  362.     TCHAR rgchDigits[] = TEXT("0123456789ABCDEF");
  363.  
  364.     lstrcpy(szHexString, TEXT("0x"));
  365.     if(cbValue > (MAX_STRING_SIZE - 3)/2 || cbValue < 0)
  366.         cbValue = (MAX_STRING_SIZE - 3)/2;
  367.  
  368.     pch = &szHexString[lstrlen(szHexString)];
  369.     for(ib=0; ib < cbValue; ib++)
  370.         {
  371.         *pch++ = rgchDigits[((LPBYTE)rgbValue)[ib] >> 4];
  372.         *pch++ = rgchDigits[((LPBYTE)rgbValue)[ib] & 0xF];
  373.         }
  374.     *pch = TEXT('\0');
  375.  
  376. } /* BinToHex() */
  377.  
  378.  
  379.  
  380. /*-----------------------------------------------------------------------*/
  381. /*      Function:               SearchForError                           */
  382. /*-----------------------------------------------------------------------*/
  383.  
  384. _inline int PASCAL SearchForError(HENV henv, HDBC hdbc,HSTMT hstmt,LPTSTR szFindState)
  385. {
  386.     TCHAR buf[MAX_STRING_SIZE];
  387.     RETCODE rc;
  388.     TCHAR szState[6];
  389.     int found = FALSE;
  390.  
  391.     for(rc = SQLError(henv, hdbc, hstmt, szState, NULL, buf, MAX_STRING_SIZE, NULL)
  392.         ; !found && (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
  393.         ; rc = SQLError(henv, NULL, NULL, szState, NULL, buf, MAX_STRING_SIZE, NULL)) 
  394.     {
  395.         found = lstrcmp(szState, szFindState) == 0;
  396.     }
  397.  
  398.     return(found);
  399.  
  400. } /* SearchForError() */
  401.  
  402.  
  403. /*-----------------------------------------------------------------------*/
  404. /*      Function:               szWrite                                  */
  405. /*-----------------------------------------------------------------------*/
  406.  
  407. _inline VOID WINAPI szWrite(LPTSTR szStr, BOOL fNewLine)
  408. {
  409.     szLogPrintf(lpSI, FALSE, szStr);
  410.     if(fNewLine)
  411.         szLogPrintf(lpSI, FALSE, TEXT("\r\n"));
  412. }
  413.  
  414. /*-----------------------------------------------------------------------*/
  415. /*      Function:               GetErrors                                     */
  416. /*-----------------------------------------------------------------------*/
  417.  
  418. VOID PASCAL GetErrors(HENV henv,HDBC hdbc,HSTMT hstmt)
  419. {
  420.     TCHAR buf[MAX_ERROR_SIZE];
  421.     TCHAR largebuf[COMBINED_SIZE];
  422.     TCHAR szState[100];
  423.     RETCODE rc=SQL_SUCCESS;
  424.  
  425.     for(rc = SQLError(henv, hdbc, hstmt, szState, NULL, buf, MAX_ERROR_SIZE, NULL)
  426.         ; RC_SUCCESSFUL(rc)
  427.         ; rc = SQLError(henv, NULL, NULL, szState, NULL, buf, MAX_ERROR_SIZE, NULL))
  428.     {
  429.         wsprintf(largebuf,TEXT("\t\t\tState: %s"), szState);
  430.         szWrite(largebuf, TRUE);
  431.         wsprintf(largebuf,TEXT("\t\t\tError: %s"), buf);
  432.         szWrite(largebuf, TRUE);
  433.     }
  434.  
  435. } /* GetErrors() */
  436.  
  437.  
  438. /*-----------------------------------------------------------------------*/
  439. /*      Function:               GetDiagRecs                                 */
  440. /*-----------------------------------------------------------------------*/
  441.  
  442. VOID PASCAL GetDiagRecs(SWORD fHandleType,SQLHANDLE hHandle)
  443. {
  444.     TCHAR        szMessageText[XLARGEBUFF]=TEXT(""),
  445.                 szBuff[XLARGEBUFF]=TEXT("");
  446.     TCHAR        szSQLState[100]=TEXT("");
  447.     RETCODE    rc=SQL_SUCCESS;
  448.     SWORD        irecRecNumber=0;
  449.     SDWORD    fNativeError=0;
  450.     SWORD        cbBufferLength=sizeof(szMessageText),
  451.                 cbTextLength=0;
  452.     SDWORD    sdNumRecs=0;
  453.  
  454.     if (fDiagFieldSupported)
  455.     {
  456.         /* Get number of diag, records */
  457.         rc = SQLGetDiagField(fHandleType, hHandle,0,SQL_DIAG_NUMBER,
  458.             &sdNumRecs,sizeof(sdNumRecs),NULL);
  459.     }
  460.  
  461.  
  462.     for(irecRecNumber=1;(irecRecNumber <= sdNumRecs) && RC_SUCCESSFUL(rc);irecRecNumber++)
  463.     {
  464.         rc = SQLGetDiagRec(fHandleType, hHandle, irecRecNumber,szSQLState,&fNativeError,
  465.             szMessageText,cbBufferLength,&cbTextLength);
  466.  
  467.         if (RC_SUCCESSFUL(rc))
  468.         {
  469.             wsprintf(szBuff,TEXT("\t\t\tState: %s"), szSQLState);
  470.             szWrite(szBuff, TRUE);
  471.             wsprintf(szBuff,TEXT("\t\t\tError: %s"), szMessageText);
  472.             szWrite(szBuff, TRUE);
  473.         }
  474.  
  475.     }
  476.  
  477.  
  478. } /* GetErrors() */
  479.  
  480.  
  481.  
  482. /*-----------------------------------------------------------------------*/
  483. /*      Function:               DisplayAllErrors                         */
  484. /*-----------------------------------------------------------------------*/
  485.  
  486. void  PASCAL DisplayAllErrors()
  487. {
  488.     if (!fDiagRecSupported)
  489.     {
  490.         GetErrors(henv,NULL,NULL);
  491.         GetErrors(NULL,hdbc,NULL);
  492.         GetErrors(NULL,NULL,hstmt);
  493.     }
  494.     else
  495.     {
  496.         GetDiagRecs(SQL_HANDLE_ENV,henv);
  497.         GetDiagRecs(SQL_HANDLE_DBC,hdbc);
  498.         GetDiagRecs(SQL_HANDLE_STMT,hstmt);
  499.         GetDiagRecs(SQL_HANDLE_DESC,hdesc);
  500.     }
  501.  
  502. } /* DisplayAllErrors() */
  503.  
  504.  
  505. /*-----------------------------------------------------------------------*/
  506. /*      Function:               RetcodeToTCHAR                            */
  507. /*-----------------------------------------------------------------------*/
  508.  
  509. LPTSTR  PASCAL RetcodeToTCHAR(RETCODE retcode, LPTSTR buf)
  510. {
  511.     switch (retcode) 
  512.         {
  513.         case SQL_SUCCESS:
  514.             lstrcpy (buf,TEXT("SQL_SUCCESS"));
  515.             break;
  516.         case SQL_ERROR:
  517.             lstrcpy (buf,TEXT("SQL_ERROR"));
  518.             break;
  519.         case SQL_SUCCESS_WITH_INFO:
  520.             lstrcpy (buf,TEXT("SQL_SUCCESS_WITH_INFO"));
  521.             break;
  522.         case SQL_NO_DATA_FOUND:
  523.             lstrcpy (buf,TEXT("SQL_NO_DATA_FOUND"));
  524.             break;
  525.         case SQL_NEED_DATA:
  526.             lstrcpy (buf,TEXT("SQL_NEED_DATA"));
  527.             break;
  528.         case SQL_INVALID_HANDLE:
  529.             lstrcpy (buf,TEXT("SQL_INVALID_HANDLE"));
  530.             break;
  531.         case SQL_STILL_EXECUTING:
  532.             lstrcpy (buf,TEXT("SQL_STILL_EXECUTING"));
  533.             break;
  534.         default:
  535.             lstrcpy(buf,TEXT("UNKNOWN rc"));
  536.         }
  537.  
  538.     return buf;
  539. }
  540.  
  541.  
  542.  
  543. //-----------------------------------------------------------------------
  544. //      Function:               ReturnCheck
  545. //-----------------------------------------------------------------------
  546.  
  547. int  PASCAL ReturnCheck(RETCODE retExpected, RETCODE retReceived, LPTSTR szFunction, 
  548.                                 LPTSTR szFile, int iLine,BOOL fDiag)
  549. {
  550.     TCHAR buf[MAX_STRING_SIZE];
  551.  
  552.     if(retExpected == retReceived)
  553.         return TRUE;
  554.  
  555.     szWrite(TEXT(""), TRUE);
  556.                         
  557.     szWrite(TEXT("\t\t\t"), FALSE);
  558.     szWrite(szFunction, TRUE);
  559.  
  560.     szWrite(TEXT("\t\t\tExpected: "), FALSE);
  561.     szWrite(RetcodeToTCHAR(retExpected, buf), TRUE);
  562.  
  563.     szWrite(TEXT("\t\t\tReceived: "), FALSE);
  564.     szWrite(RetcodeToTCHAR(retReceived, buf), TRUE);
  565.  
  566.     if (!fDiag)
  567.         DisplayAllErrors();
  568.  
  569.     wsprintf(buf,TEXT("\t\t\t%s: %d"), szFile, iLine);
  570.     szWrite(buf, TRUE);
  571.  
  572.     szWrite(TEXT("\t\t\t --------  "), TRUE);
  573.  
  574.     lpSI->failed++;
  575.  
  576.     return FALSE;
  577. }
  578.  
  579. //-----------------------------------------------------------------------
  580. //      Function:               ErrsHandle
  581. //-----------------------------------------------------------------------
  582.  
  583. int  PASCAL ErrsHandle(SWORD fHandleType,SQLHANDLE hHandle, RETCODE retExpected,
  584.     RETCODE retReceived, LPTSTR szFunction, LPTSTR szFile, int iLine,BOOL fDiag)
  585. {
  586.     TCHAR buf[MAX_STRING_SIZE];
  587.  
  588.     if(retExpected == retReceived)
  589.         return TRUE;
  590.  
  591.     szWrite(TEXT(""), TRUE);
  592.                         
  593.     szWrite(TEXT("\t\t\t"), FALSE);
  594.     szWrite(szFunction, TRUE);
  595.  
  596.     szWrite(TEXT("\t\t\tExpected: "), FALSE);
  597.     szWrite(RetcodeToTCHAR(retExpected, buf), TRUE);
  598.  
  599.     szWrite(TEXT("\t\t\tReceived: "), FALSE);
  600.     szWrite(RetcodeToTCHAR(retReceived, buf), TRUE);
  601.  
  602.     if (!fDiag)
  603.         GetDiagRecs(fHandleType,hHandle);
  604.  
  605.     wsprintf(buf,TEXT("\t\t\t%s: %d"), szFile, iLine);
  606.     szWrite(buf, TRUE);
  607.  
  608.     szWrite(TEXT("\t\t\t --------  "), TRUE);
  609.  
  610.     lpSI->failed++;
  611.  
  612.     return FALSE;
  613. }
  614.  
  615. /*------------------------------------------------------------------------------
  616. /    Function:    FindError
  617. /    Purpose:    Find the expected error message. Display a failure if not found.
  618. /*----------------------------------------------------------------------------*/
  619.  
  620. BOOL PASCAL FindError(SWORD fHandleType, LPTSTR szFindState)
  621. {
  622.     SQLHANDLE handle = SQL_NULL_HANDLE;
  623.     SWORD irec;
  624.     TCHAR szErrorMsg[SQL_MAX_MESSAGE_LENGTH];
  625.     RETCODE rc;
  626.     TCHAR szState[6];
  627.  
  628.     switch(fHandleType)
  629.     {
  630.         case SQL_HANDLE_ENV:
  631.             handle = henv;
  632.             break;
  633.  
  634.         case SQL_HANDLE_DBC:
  635.             handle = hdbc;
  636.             break;
  637.  
  638.         case SQL_HANDLE_STMT:
  639.             handle = hstmt;
  640.             break;
  641.  
  642.         case SQL_HANDLE_DESC:
  643.             if(!Supported(SQL_API_SQLGETDIAGREC))
  644.                 return TRUE;
  645.  
  646.             handle = hdesc;
  647.             break;
  648.  
  649.         default:
  650.             DISPLAYERROR(TEXT("FindError"), TEXT("invalid fHandleType"));
  651.             return FALSE;
  652.     }
  653.  
  654.     for(irec = 1
  655.         ; rc = SQLGetDiagRec(fHandleType, handle, irec, szState, NULL, szErrorMsg, SQL_MAX_MESSAGE_LENGTH, NULL)
  656.         , RC_SUCCESSFUL(rc)
  657.         ; irec++)
  658.     {
  659.         if(lstrcmp(szState, szFindState) == 0)
  660.             return TRUE;
  661.     }
  662.     return FALSE;
  663.  
  664. } /* FindError() */
  665.  
  666. /*------------------------------------------------------------------------------
  667.  *    Function:    CompareWithExpected
  668.  *    Checks data in rgbValue against expected value given row, col, and rgFields.
  669.  *    Posts an error if mismatch
  670.  * ----------------------------------------------------------------------------*/
  671. void CompareWithExpected(PTR rgbValue, SDWORD * pcbValue, UWORD row, UWORD icol, FIELDINFO  *rgFields)
  672. {
  673.     LPTSTR   pch=NULL;
  674.     TCHAR szExpBuf[MAX_STRING_SIZE]=TEXT("");
  675.     TCHAR * stopstr;
  676.  
  677.     pch = qtMakeData(row-1, icol-1, &rgFields[icol-1], szExpBuf);
  678.  
  679.     // Field is not READ ONLY, compare the value we inserted
  680.     if(pch) 
  681.     {
  682.          // Where row and column match and field is nullable, a NULL exists
  683.         if (icol-1 == row-1 && rgFields[icol-1].nullable)
  684.         {
  685.             // Post an error if not SQL_NULL_DATA
  686.             if (*pcbValue != SQL_NULL_DATA)
  687.                 DISPLAYERROR(TEXT("Simulate BindCol"),TEXT("Didn't return SQL_NULL_DATA"));
  688.         }
  689.         else
  690.         {
  691.             BOOL bCompare;
  692.             TCHAR * pstr=szExpBuf;    // Pointer to start of expected string
  693.  
  694.             switch(rgFields[icol-1].wSQLType)
  695.             {
  696.                 case SQL_BIT:
  697.                 case SQL_TINYINT:
  698.                 case SQL_SMALLINT:
  699.                 case SQL_INTEGER:
  700.                     // Compare the data values as long // tcsncmp
  701.                     bCompare=(_ttol(rgbValue) == _ttol(pstr));
  702.                     break;
  703.                 case SQL_NUMERIC:
  704.                 case SQL_DECIMAL:
  705.                 case SQL_FLOAT:
  706.                 case SQL_REAL:
  707.                 case SQL_DOUBLE:
  708.                     // Compare the data values as doubles strtod
  709.                     bCompare=(_tcstod(rgbValue, &stopstr) == _tcstod(pstr, &stopstr));
  710.                     break;
  711.                 case SQL_DATE:
  712.                 case SQL_TIME:
  713.                 case SQL_TIMESTAMP:
  714.                 case SQL_TYPE_DATE:
  715.                 case SQL_TYPE_TIME:
  716.                 case SQL_TYPE_TIMESTAMP:
  717.                     pstr=szExpBuf+lstrlen(TEXT("{ts '"));
  718.                     // Replace second ' with '\0'                                    '
  719.                     _tcstok(pstr, TEXT("'"));
  720.                     if (lstrlen(rgbValue) > lstrlen(TEXT("1994-10-10 10:00:00")))
  721.                         lstrcat(pstr, TEXT(".000"));
  722.                     bCompare=(!_tcsncmp(rgbValue, pstr, rgFields[icol-1].precision));
  723.                     break;
  724.                 default:
  725.                     bCompare=(!_tcsncmp(rgbValue, pstr, lstrlen(pstr)));
  726.             }
  727.  
  728.             // Compare the data values as char 
  729.             if (!bCompare)
  730.             {
  731.                 DISPLAYERROR(TEXT("Simulate BindCol"),TEXT("Returned data didn't match"));
  732.                 szWrite(TEXT("\t\t\tExpected: "), FALSE);
  733.                 szWrite(pstr, TRUE);
  734.                 szWrite(TEXT("\t\t\tReceived: "), FALSE);
  735.                 szWrite(rgbValue, TRUE);
  736.             }
  737.         }
  738.     }
  739. } //CompareWithExpected
  740.  
  741. //-----------------------------------------------------------------------
  742. //      Function:               ResetHstmt
  743. //-----------------------------------------------------------------------
  744. void ResetHstmt(SQLHSTMT * phstmt)
  745. {
  746.     SQLRETURN rc;
  747.  
  748.     // Free and reallocate stmt handle to clean up
  749.     rc=SQLFreeHandle(SQL_HANDLE_STMT, *phstmt);
  750.     ERRSHANDLE(SQL_HANDLE_STMT, *phstmt, SQL_SUCCESS, rc, szSQLFREESTMT);
  751.     rc=SQLAllocHandle(SQL_HANDLE_STMT, hdbc, phstmt);
  752.     RETCHECK(SQL_SUCCESS, rc,szSQLALLOCHANDLE);
  753. }
  754.  
  755. /*-----------------------------------------------------------------------*/
  756. /*      Function:               GetSomeData                              */
  757. /*-----------------------------------------------------------------------*/
  758.  
  759. VOID PASCAL GetSomeData(HSTMT lhstmt, LPTSTR szTableName,BOOL fBindCol,
  760.                                 FIELDINFO  rgField)
  761. {
  762.     RETCODE    rc=SQL_SUCCESS;
  763.     SDWORD    cbValue=0;
  764.     TCHAR        szQuery[XLARGEBUFF]=TEXT(""),
  765.                 szBuff[XLARGEBUFF]=TEXT("");
  766.     TCHAR        szErrMsg[MAX_STRING_SIZE]=TEXT(""),
  767.                 szDataItem[XLARGEBUFF]=TEXT("");
  768.     LPTSTR   pch=NULL;
  769.  
  770.     pch = qtMakeData(0, 0,&rgField, szDataItem);
  771.  
  772.     wsprintf(szQuery,szSELECTSTAR,szTableName);
  773.     rc=SQLExecDirect(lhstmt,szQuery,SQL_NTS);
  774. //    RETCHECK(SQL_SUCCESS,rc,szSQLEXECDIRECT);
  775.  
  776.     if (fBindCol)
  777.     {
  778.         rc = SQLBindCol(lhstmt, 1, SQL_C_TCHAR, szBuff, sizeof(szBuff),&cbValue);
  779. //        RETCHECK(SQL_SUCCESS, rc, szSQLBINDCOL);
  780.     }
  781.  
  782.     rc = SQLFetch(lhstmt);
  783. //    RETCHECK(SQL_SUCCESS, rc,szSQLFETCH);
  784.  
  785.     if (!fBindCol)
  786.     {
  787.         rc = SQLGetData(lhstmt,1, SQL_C_TCHAR,szBuff, sizeof(szBuff), NULL);
  788. //        RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA);
  789.     }
  790.  
  791.     lstrcmp(szDataItem,szBuff);
  792.  
  793. } /* GetSomeData() */
  794.  
  795.  
  796.  
  797. /*-----------------------------------------------------------------------*/
  798. /*      Function:               SelectFromTable                          */
  799. /*-----------------------------------------------------------------------*/
  800.  
  801. _inline RETCODE PASCAL SelectFromTable(QTSTRUCT *lpqt)
  802. {
  803.     RETCODE    rc=SQL_SUCCESS;
  804.     TCHAR        szQuery[LARGEBUFF];
  805.  
  806.     wsprintf(szQuery,TEXT("select %s from %s"), 
  807.     //wsprintf(szQuery,TEXT("select %s from %s order by %s"), 
  808.         lpqt->szColNames, lpqt->szTableName/*, lpqt->szColNames*/);
  809.  
  810.     rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
  811.     RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  812.  
  813.     return(rc);
  814.  
  815. } /* SelectFromTable() */
  816.  
  817. /*-----------------------------------------------------------------------*/
  818. /*      Function:               SelectFromTableFetch                     */
  819. /*-----------------------------------------------------------------------*/
  820.  
  821. _inline RETCODE PASCAL SelectFromTableFetch(QTSTRUCT *lpqt, TCHAR* szColName)
  822. {
  823.     RETCODE    rc=SQL_SUCCESS;
  824.     TCHAR        szQuery[LARGEBUFF];
  825.  
  826.     wsprintf(szQuery,TEXT("select %s from %s order by %s"), 
  827.         lpqt->szColNames, lpqt->szTableName, szColName);
  828.  
  829.     rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
  830.     if((SQL_SUCCESS!=rc) && (SQL_SUCCESS_WITH_INFO!=rc)){
  831.         RETCHECK(SQL_SUCCESS_WITH_INFO, rc,szSQLEXECDIRECT);
  832.         return SQL_NO_DATA;
  833.     }
  834.  
  835.     return SQL_SUCCESS;
  836. } /* SelectFromTableFetch() */
  837.  
  838. //-----------------------------------------------------------------------
  839. //      Function:               AllocHstmt
  840. //-----------------------------------------------------------------------
  841.  
  842. _inline BOOL PASCAL AllocHstmt()
  843. {
  844.     BOOL        fFailed=FALSE;
  845.     RETCODE    rc=SQL_SUCCESS;
  846.  
  847.     if (Supported(SQL_API_SQLALLOCHANDLE))
  848.     {
  849.         rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc, &hstmt);
  850.         if(!RETCHECK(SQL_SUCCESS, rc, szSQLALLOCHANDLE))
  851.             fFailed=TRUE;
  852.     }
  853.     else
  854.     {
  855.         rc = SQLAllocStmt(hdbc, &hstmt);
  856.         if(!RETCHECK(SQL_SUCCESS, rc, szSQLALLOCSTMT))
  857.             fFailed=TRUE;
  858.     }
  859.  
  860.  
  861.     return(fFailed);
  862.  
  863. } //AllocHstmt()
  864.  
  865.  
  866.  
  867. //-----------------------------------------------------------------------
  868. //      Function:               AllocHdbc
  869. //-----------------------------------------------------------------------
  870.  
  871. _inline BOOL PASCAL AllocHdbc(HDBC *phdbc)
  872. {
  873.     BOOL        fFailed=FALSE;
  874.     RETCODE    rc=SQL_SUCCESS;
  875.  
  876.     if (Supported(SQL_API_SQLALLOCHANDLE))
  877.     {
  878.         rc = SQLAllocHandle(SQL_HANDLE_DBC,henv, phdbc);
  879.         if(!RETCHECK(SQL_SUCCESS, rc, szSQLALLOCHANDLE))
  880.             fFailed=TRUE;
  881.     }
  882.     else
  883.     {
  884.         rc = SQLAllocConnect(henv, phdbc);
  885.         if(!RETCHECK(SQL_SUCCESS, rc, szSQLALLOCCONNECT))
  886.             fFailed=TRUE;
  887.     }
  888.  
  889.  
  890.     return(fFailed);
  891.  
  892. } //AllocHdbc()
  893.  
  894.  
  895. //-----------------------------------------------------------------------
  896. //      Function:                    AllocHenv
  897. //-----------------------------------------------------------------------
  898.  
  899. _inline BOOL PASCAL PASCAL AllocHenv()
  900. {
  901.     BOOL        fFailed=FALSE;
  902.     RETCODE    rc=SQL_SUCCESS;
  903.  
  904.     rc = SQLAllocEnv(&henv);
  905.     if (!RETCHECK(SQL_SUCCESS, rc,szSQLALLOCENV))
  906.         fFailed=TRUE;
  907.  
  908.     return(fFailed);
  909.  
  910. } //AllocHenv()
  911.  
  912. //-----------------------------------------------------------------------
  913. //      Function:               SetStatementAttributes
  914. //-----------------------------------------------------------------------
  915.  
  916. _inline BOOL PASCAL SetStatementAttributes(UWORD fAttr, PTR rgbValue)
  917. {
  918.     RETCODE    rc=SQL_SUCCESS;
  919.     TCHAR        szAPI[MEDBUFF];
  920.     BOOL        fFailed=FALSE;
  921.  
  922.     if (Supported(SQL_API_SQLSETSTMTATTR))
  923.     {
  924.         rc = SQLSetStmtAttr(hstmt,(SDWORD)fAttr,rgbValue,sizeof(UDWORD));
  925.         lstrcpy(szAPI,szSQLSETSTMTATTR);
  926.     }
  927.     else
  928.     {
  929.         rc = SQLSetStmtOption(hstmt,fAttr,(UDWORD)rgbValue);
  930.         lstrcpy(szAPI,szSQLSETSTMTOPTION);
  931.     }
  932.  
  933.     if (rc != SQL_SUCCESS)
  934.     {
  935.         if(!FindError(SQL_HANDLE_STMT,szHYC00))
  936.             RETCHECK(SQL_SUCCESS, rc,szAPI);
  937.  
  938.         fFailed=TRUE;
  939.     }
  940.  
  941.     return(fFailed);
  942.  
  943. } //SetStatementAttributes()
  944.  
  945.  
  946.  
  947. //-----------------------------------------------------------------------
  948. //      Function:               SetConnectionAttributes
  949. //-----------------------------------------------------------------------
  950.  
  951. _inline BOOL PASCAL SetConnectionAttributes(HDBC lhdbc,UWORD fAttr, UDWORD rgbValue)
  952. {
  953.     RETCODE    rc=SQL_SUCCESS;
  954.     TCHAR        szAPI[MEDBUFF];
  955.     BOOL        fFailed=FALSE;
  956.  
  957.     if (Supported(SQL_API_SQLSETCONNECTATTR))
  958.     {
  959.         rc = SQLSetConnectAttr(lhdbc,(SDWORD)fAttr,(PTR)rgbValue,sizeof(UDWORD));
  960.         lstrcpy(szAPI,szSQLSETCONNECTATTR);
  961.     }
  962.     else
  963.     {
  964.         rc = SQLSetConnectOption(lhdbc,fAttr,rgbValue);
  965.         lstrcpy(szAPI,szSQLSETCONNECTOPTION);
  966.     }
  967.  
  968.     if (rc != SQL_SUCCESS)
  969.     {
  970.         if(!FindError(SQL_HANDLE_DBC,szHYC00))
  971.             RETCHECK(SQL_SUCCESS, rc,szAPI);
  972.  
  973.         fFailed=TRUE;
  974.     }
  975.  
  976.     return(fFailed);
  977.  
  978. } //SetConnectionAttributes()
  979.  
  980.  
  981.  
  982. //-----------------------------------------------------------------------
  983. //      Function:               FreeStmt
  984. //-----------------------------------------------------------------------
  985.  
  986. _inline BOOL PASCAL FreeStmt(UWORD fOption)
  987. {
  988.     RETCODE    rc=SQL_SUCCESS;
  989.  
  990.     if (Supported(SQL_API_SQLFREEHANDLE) && (fOption == SQL_DROP))
  991.     {
  992.         rc = SQLFreeHandle(SQL_HANDLE_STMT,hstmt);
  993.         RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE);
  994.     }
  995.     else
  996.     {
  997.         rc = SQLFreeStmt(hstmt, fOption);
  998.         RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT);
  999.     }
  1000.  
  1001.     return(RC_NOTSUCCESSFUL(rc));
  1002.  
  1003. } //FreeStmt()
  1004.  
  1005. //-----------------------------------------------------------------------
  1006. //      Function:               DropHdbc
  1007. //-----------------------------------------------------------------------
  1008.  
  1009. VOID PASCAL DropHdbc(HDBC hdbc)
  1010. {
  1011.     RETCODE rc=SQL_SUCCESS;
  1012.  
  1013.     if (Supported(SQL_API_SQLFREEHANDLE))
  1014.     {
  1015.         rc = SQLFreeHandle(SQL_HANDLE_DBC,hdbc);
  1016.         RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE);
  1017.     }
  1018.     else
  1019.     {
  1020.         rc = SQLFreeConnect(hdbc);
  1021.         RETCHECK(SQL_SUCCESS, rc,szSQLFREECONNECT);
  1022.     }
  1023.  
  1024. } //DropHdbc()
  1025.  
  1026.  
  1027.  
  1028. //-----------------------------------------------------------------------
  1029. //      Function:               DropHenv
  1030. //-----------------------------------------------------------------------
  1031.  
  1032. _inline VOID PASCAL DropHenv()
  1033. {
  1034.     RETCODE rc=SQL_SUCCESS;
  1035.  
  1036.     if (Supported(SQL_API_SQLFREEHANDLE))
  1037.     {
  1038.         rc = SQLFreeHandle(SQL_HANDLE_ENV,henv);
  1039.         RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE);
  1040.     }
  1041.     else
  1042.     {
  1043.         rc = SQLFreeEnv(henv);
  1044.         RETCHECK(SQL_SUCCESS, rc,szSQLFREEENV);
  1045.     }
  1046.  
  1047. } //DropHenv()
  1048.  
  1049.  
  1050. //-----------------------------------------------------------------------
  1051. //      Function:               ClearErrorQueue
  1052. //-----------------------------------------------------------------------
  1053.  
  1054. VOID PASCAL ClearErrorQueue()
  1055. {
  1056.     TCHAR szErrMsg[MAX_STRING_SIZE];
  1057.     TCHAR szState[6];
  1058.  
  1059.     /* Eat up the SQL_SUCCESS_WITH_INFO error record */
  1060.     while (RC_SUCCESSFUL(SQLError(NULL, hdbc,NULL, szState, NULL, 
  1061.         szErrMsg, sizeof(szErrMsg), NULL)))
  1062.             ;
  1063. }
  1064.  
  1065.  
  1066. //-----------------------------------------------------------------------
  1067. //      Function:               Is3XDriver
  1068. //-----------------------------------------------------------------------
  1069.  
  1070. BOOL PASCAL Is3XDriver(HDBC hdbc,QTSTRUCT *lpqt)
  1071. {
  1072.     RETCODE        rc=SQL_SUCCESS;
  1073.     LPTSTR        pch=NULL;
  1074.     BOOL            f3XDriver=FALSE;
  1075.  
  1076.     rc = SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, lpqt->buf, MAX_STRING_SIZE, NULL);
  1077.     if(RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO))
  1078.     {
  1079.         pch = _tcstok(lpqt->buf,TEXT("."));
  1080.  
  1081.         if (!_tcsnccmp(pch,TEXT("02"), 2))
  1082.         {
  1083.             pch = _tcstok(NULL,TEXT("."));
  1084.         
  1085.             if(!_tcsnccmp(pch,TEXT("00"), 2))
  1086.                 DISPLAYERROR(szSQLGETINFO,TEXT("Driver returned ODBC version 2.00 which is no longer supported.  Please upgrade to 2.01"));
  1087.             
  1088.         }
  1089.         else if (!_tcsnccmp(pch,TEXT("03"), 2))
  1090.             f3XDriver=TRUE;
  1091.     }
  1092.  
  1093.     uDriverODBCVer=_ttoi(lpqt->buf);
  1094.  
  1095.     return(f3XDriver);
  1096.  
  1097. } //Is3XDriver()
  1098.  
  1099.  
  1100. //-----------------------------------------------------------------------
  1101. //      Function:               Connect
  1102. //-----------------------------------------------------------------------
  1103.  
  1104. BOOL  PASCAL Connect(lpSERVERINFO lpSI,QTSTRUCT  *lpqt)
  1105. {
  1106.     RETCODE    rc=SQL_SUCCESS;
  1107.     SDWORD sdwAppVer;
  1108.  
  1109. /* The signal for test to use it's
  1110.     own allocated handles, is if the a server name is passed in.  If it
  1111.     is not, the test should use the hdbc passed in */
  1112.  
  1113.     /* ****************** Allocate Env ************************* */
  1114.     if (AllocHenv())
  1115.         goto ConnectErrorRet;
  1116.  
  1117.     /* ****************** Set Application Version ************************* */
  1118.     rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3,
  1119.         SQL_IS_UINTEGER);
  1120.     if(!RETCHECK(SQL_SUCCESS, rc, szSQLSETENVATTR))
  1121.         goto ConnectErrorRet;
  1122.  
  1123.     /* ****************** Allocate Connection ************************* */
  1124.  
  1125.     rc = SQLAllocConnect(henv, &hdbc);
  1126.     if(!RETCHECK(SQL_SUCCESS, rc, szSQLALLOCCONNECT))
  1127.         goto ConnectErrorRet;
  1128.  
  1129.     /* ****************** Set Connection Attributes ************************* */
  1130.     rc = SQLSetConnectOption(hdbc,SQL_ODBC_CURSORS,lpSI->vCursorLib);
  1131.  
  1132.     if(!FindError(SQL_HANDLE_DBC,szHYC00))
  1133.         if (!RETCHECK(SQL_SUCCESS, rc,szSQLSETCONNECTOPTION))
  1134.         goto ConnectErrorRet;
  1135.  
  1136.     /* create a DriverConnect string */
  1137.     wsprintf(lpqt->sz, TEXT("dsn=%s;uid=%s;pwd=%s;"),
  1138.         lpSI->szValidServer0,
  1139.         lpSI->szValidLogin0,
  1140.         lpSI->szValidPassword0);
  1141.  
  1142.     /* since SQL_DRIVER_COMPLETE is used, it is possible that the
  1143.     driver will bring up a dialog asking for more information. */
  1144.     rc = SQLDriverConnect(hdbc, lpSI->hwnd, lpqt->sz,
  1145.         SQL_NTS, lpqt->buf, MAX_STRING_SIZE, NULL, SQL_DRIVER_COMPLETE);
  1146.     
  1147.     if (RC_NOTSUCCESSFUL(rc))
  1148.     {
  1149.         if (!RETCHECK(SQL_SUCCESS, rc,szSQLDRIVERCONNECT))
  1150.             goto ConnectErrorRet;
  1151.     }
  1152.     else
  1153.         ClearErrorQueue();
  1154.  
  1155.  
  1156.     rc = SQLDisconnect(hdbc);
  1157.     RETCHECK(SQL_SUCCESS, rc,szSQLDISCONNECT);
  1158.  
  1159.     rc = SQLConnect(hdbc, lpSI->szValidServer0, SQL_NTS,
  1160.                         lpSI->szValidLogin0, SQL_NTS,
  1161.                         lpSI->szValidPassword0, SQL_NTS);
  1162.  
  1163.     if (RC_SUCCESSFUL(rc))
  1164.         ClearErrorQueue();
  1165.     else if (!RETCHECK(SQL_SUCCESS, rc,szSQLCONNECT))
  1166.         goto ConnectErrorRet;
  1167.  
  1168.     // Set the global 3.0 driver flag
  1169.     g_f3XDriver=Is3XDriver(hdbc,lpqt);
  1170.  
  1171.     // We're now connected, check application version and adjust expected error
  1172.     // states appropriately.
  1173.     rc = SQLGetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, &sdwAppVer, SQL_IS_UINTEGER, NULL);
  1174.     RETCHECK(SQL_SUCCESS, rc,szSQLGETENVATTR);
  1175.  
  1176.     if (RC_SUCCESSFUL(rc) && (SQL_OV_ODBC2 == sdwAppVer))
  1177.     {
  1178.         lstrcpy(szHY009, TEXT("S1009"));
  1179.         lstrcpy(szHYC00, TEXT("S1C00"));
  1180.     }
  1181.  
  1182.     return(FALSE);
  1183.  
  1184. ConnectErrorRet:
  1185.  
  1186.     return(TRUE);
  1187.  
  1188. } //Connect()
  1189.  
  1190.  
  1191. //-----------------------------------------------------------------------
  1192. //      Function:               IgnoreType
  1193. //-----------------------------------------------------------------------
  1194.  
  1195. BOOL  PASCAL IgnoreType(LPTSTR szType,SWORD wSQLType)
  1196. {
  1197.     BOOL fIgnore=FALSE;
  1198.  
  1199. /* If a line below is compiled in, that type will not be used in creating
  1200.  the table.  (useful for when one specific type is causing problems in
  1201.  a particular test, this way the test can be run for all other types)
  1202. */
  1203.  
  1204.     if (!lstrcmp(szType,TEXT("LONG RAW")) ||
  1205.          !lstrcmp(szType,TEXT("LONG VARTCHAR")) ||
  1206.           !lstrcmp(szType,TEXT("LONG VARTCHAR FOR BIT DATA")))
  1207.         {
  1208.          fIgnore=TRUE;
  1209.         }
  1210.  
  1211.     //if (wSQLType != SQL_CHAR)
  1212.     //    fIgnore=TRUE;
  1213.  
  1214.     return(fIgnore);
  1215.  
  1216. } //IgnoreType()
  1217.             
  1218.     
  1219. //-----------------------------------------------------------------------
  1220. //      Function:               CheckConformanceLevel
  1221. //-----------------------------------------------------------------------
  1222.  
  1223. UWORD  PASCAL CheckConformanceLevel()
  1224. {
  1225.     RETCODE     rc=SQL_SUCCESS;
  1226.     UWORD        fIndex=0;
  1227.     SWORD        cb=0;
  1228.  
  1229.     rc = SQLGetInfo(hdbc, SQL_ODBC_SQL_CONFORMANCE, &fIndex,
  1230.         sizeof (fIndex), &cb);
  1231.     RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO);
  1232.  
  1233.     if(fIndex != 0 && fIndex != 1 && fIndex != 2) {
  1234.         /* one of these two values should always be returned */
  1235.         DISPLAYERROR(szSQLGETINFO,TEXT("SQL_ODBC_API_CONFORMANCE - invalid value"));
  1236.     }
  1237.  
  1238.     return(fIndex);
  1239.  
  1240. } //CheckConformanceLevel()
  1241.  
  1242. /*-----------------------------------------------------------------------*/
  1243. /*      Function:               TestConnectionOptions                             */
  1244. /*-----------------------------------------------------------------------*/
  1245.  
  1246. void  PASCAL TestConnectionOptions()
  1247. {
  1248.     RETCODE    rc=SQL_SUCCESS;
  1249.     SDWORD    sdw,
  1250.                 cbValue=0;
  1251.     BOOL        fConnectOption=TRUE;
  1252.     TCHAR        szAPI[MEDBUFF];
  1253.     HDBC        lhdbc=NULL;
  1254.  
  1255.  
  1256.     rc=SQLAllocConnect(henv,&lhdbc);
  1257.     RETCHECK(SQL_SUCCESS, rc,szSQLALLOCCONNECT);
  1258.     
  1259.     SetConnectionAttributes(lhdbc,SQL_ACCESS_MODE,SQL_MODE_READ_WRITE);
  1260.  
  1261.     SetConnectionAttributes(lhdbc,SQL_AUTOCOMMIT,TRUE);
  1262.  
  1263.     if (SetConnectionAttributes(lhdbc,SQL_LOGIN_TIMEOUT,TEST_CONNECT_OPTION))
  1264.         fConnectOption = FALSE;
  1265.  
  1266.     if (Supported(SQL_API_SQLGETCONNECTATTR))
  1267.     {
  1268.         rc = SQLGetConnectAttr(lhdbc, SQL_LOGIN_TIMEOUT, (PTR)&sdw,0,&cbValue);
  1269.         lstrcpy(szAPI,szSQLGETCONNECTATTR);
  1270.     }
  1271.     else
  1272.     {
  1273.         rc = SQLGetConnectOption(lhdbc, SQL_LOGIN_TIMEOUT, &sdw);
  1274.         lstrcpy(szAPI,szSQLSETCONNECTOPTION);
  1275.     }
  1276.  
  1277.  
  1278.     if(rc != SQL_SUCCESS)
  1279.     {
  1280.         if(!FindError(SQL_HANDLE_DBC,szHYC00))
  1281.             RETCHECK(SQL_SUCCESS, rc,szAPI);
  1282.     }
  1283.     else
  1284.     {
  1285.         if(sdw != TEST_CONNECT_OPTION && fConnectOption)
  1286.             DISPLAYERROR(szAPI,TEXT("SQL_LOGIN_TIMEOUT returned incorrect value"));
  1287.     }
  1288.  
  1289.     rc=SQLFreeConnect(lhdbc);
  1290.     RETCHECK(SQL_SUCCESS, rc,szSQLFREECONNECT);
  1291.  
  1292. } //TestConnectionOptions()
  1293.  
  1294.  
  1295.  
  1296. /*-----------------------------------------------------------------------*/
  1297. /*      Function:            CanAllocHdesc                                        */
  1298. /*-----------------------------------------------------------------------*/
  1299.  
  1300. BOOL PASCAL CanAllocHdesc()
  1301. {
  1302.     BOOL fSupported=FALSE;
  1303.  
  1304.     /* Allocate an hdesc: */
  1305.     if(Supported(SQL_API_SQLALLOCHANDLE))
  1306.         fSupported = RC_SUCCESSFUL(SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc));
  1307.  
  1308.     return(fSupported);
  1309.  
  1310. }
  1311.  
  1312.  
  1313. /*-----------------------------------------------------------------------*/
  1314. /*      Function:            SetErrorCondition                                    */
  1315. /*-----------------------------------------------------------------------*/
  1316.  
  1317. VOID PASCAL SetErrorCondition(SWORD fHandleType)
  1318. {
  1319.     RETCODE rc=SQL_SUCCESS;
  1320.  
  1321.     /* The following are used to produce "(S1)HY009" SQL State */
  1322.     switch (fHandleType)
  1323.     {
  1324.         case SQL_HANDLE_ENV:
  1325.             rc = SQLAllocConnect(henv, NULL);
  1326.             break;
  1327.         case SQL_HANDLE_DBC:
  1328.             rc = SQLAllocStmt(hdbc, NULL);
  1329.             break;
  1330.         case SQL_HANDLE_STMT:
  1331.             rc = SQLExecDirect(hstmt, NULL, SQL_NTS);        // Produces a DM error
  1332.             break;
  1333.         case SQL_HANDLE_DESC:
  1334.             rc = SQLGetDescField(hdesc, 0, SQL_DESC_AUTO_UNIQUE_VALUE, NULL, 0, NULL);
  1335.             break;
  1336.     }
  1337.  
  1338. } //SetErrorCondition()
  1339.  
  1340.  
  1341.  
  1342. VOID PASCAL CheckData(SWORD fHandleType,UWORD uwDescField, PTR rgbValue,LPTSTR szDataSourceName)
  1343. {
  1344.     TCHAR            szBuff[MEDBUFF]=TEXT("");
  1345.     LPTSTR        pszExpState=szHY009;
  1346.  
  1347.     if (fHandleType == SQL_HANDLE_DESC)
  1348.         pszExpState=szHY091;
  1349.  
  1350.     switch(uwDescField)
  1351.     {
  1352.         case SQL_DIAG_RETURNCODE:
  1353.             {
  1354.                 RETCODE rcRec=*(RETCODE *)rgbValue;
  1355.                 
  1356.                 if (rcRec!= SQL_ERROR)
  1357.                 {
  1358.                     wsprintf(szBuff,TEXT("\t\t\tSQL_DIAG_RETURN_CODE\tReceived: %d\tExpected: %d"),rcRec,-1);
  1359.                 }
  1360.             }
  1361.             break;
  1362.         
  1363.         case SQL_DIAG_SQLSTATE:
  1364.             {
  1365.                 if (lstrcmp((LPTSTR)rgbValue,pszExpState))
  1366.                 {
  1367.                     wsprintf(szBuff,TEXT("\t\t\tSQL_DIAG_SQLSTATE\tReceived: %s\tExpected: %s"),(LPTSTR)rgbValue,pszExpState);
  1368.                 }
  1369.             }
  1370.             break;
  1371.         case SQL_DIAG_CLASS_ORIGIN:
  1372.             {
  1373.                 if (lstrcmp((LPTSTR)rgbValue,szISO))
  1374.                     wsprintf(szBuff,TEXT("\t\t\tSQL_DIAG_CLASS_ORIGIN\tReceived: %s\tExpected: %s"),(LPTSTR)rgbValue,szISO);
  1375.             }
  1376.             break;
  1377.         case SQL_DIAG_SUBCLASS_ORIGIN:
  1378.             {
  1379.                 if (lstrcmp((LPTSTR)rgbValue,szISO))
  1380.                     wsprintf(szBuff,TEXT("\t\t\tSQL_DIAG_CLASS_ORIGIN\tReceived: %s\tExpected: %s"),(LPTSTR)rgbValue,szISO);
  1381.             }
  1382.             break;
  1383.         case SQL_DIAG_NUMBER:
  1384.             {
  1385.                 SDWORD cRecs=*(SDWORD *)rgbValue;
  1386.                 if (cRecs != 1)
  1387.                     wsprintf(szBuff,TEXT("\t\t\tSQL_DIAG_NUMBER\tReceived: %d\tExpected: %d"),cRecs,1);
  1388.             }
  1389.             break;
  1390.         case SQL_DIAG_SERVER_NAME:
  1391.             {
  1392.                 switch(fHandleType)
  1393.                 {
  1394.                 case SQL_HANDLE_DBC:
  1395.                 case SQL_HANDLE_STMT:
  1396.                     if (lstrcmp((LPTSTR)rgbValue,szDataSourceName))
  1397.                         wsprintf(szBuff,TEXT("\t\t\tSQL_DIAG_SERVER_NAME\tReceived: %s\tExpected: %s"),(LPTSTR)rgbValue,szDataSourceName);
  1398.                     break;
  1399.                 }
  1400.             }
  1401.             break;
  1402.         default:
  1403.             break;
  1404.  
  1405.     }
  1406.  
  1407.     if (*szBuff)
  1408.         DISPLAYERROR(szSQLGETDIAGREC,szBuff);
  1409.  
  1410. } /* CheckData() */
  1411.  
  1412.  
  1413. /*------------------------------------------------------------------------------
  1414. /    Function:    TestDiagRec                                              
  1415. /    Purpose:    For each type of handle, generate an error. If SQLGetDiagField      
  1416. /                is not supported, verify the appropriate DM error is returned.      
  1417. /                Otherwise, verify SQLGetDiagField returns the expected error        
  1418. /                information. If SQLGetDiagRec is not supported, verify the          
  1419. /                appropriate DM error is returned. Otherwise, verify                 
  1420. /                SQLGetDiagField returns the expected error information. If          
  1421. /                SQLGetDiagRec is supported, compare its output with that of         
  1422. /                SQLGetDiagField.                                                    
  1423. /*----------------------------------------------------------------------------*/
  1424.  
  1425. void PASCAL TestDiagRec()
  1426. {
  1427.     SQLRETURN    rcFunction, 
  1428.                     rc=SQL_SUCCESS;
  1429.     SWORD            cbErrorMsg;
  1430.     SDWORD        fNativeError;
  1431.     UWORD            iHandle=0,
  1432.                     iField=0,
  1433.                     cHandles;
  1434.  
  1435.     SDWORD        *pfNativeError = NULL;
  1436.     LPTSTR        pchMessageText = NULL;
  1437.  
  1438.     TCHAR            szDataSourceName[MAX_STRING_SIZE] = TEXT("");
  1439.     TCHAR            szState[SQL_SQLSTATE_SIZE+1];
  1440.     TCHAR            szErrorMsg[SQL_MAX_MESSAGE_LENGTH];
  1441.     TCHAR            szAPI[MEDBUFF]=TEXT("");
  1442.     TCHAR            szBuff[MEDBUFF]=TEXT("");
  1443.  
  1444.     LPTSTR        pszExpState=szHY009;
  1445.     RETCODE        rcExp=SQL_SUCCESS;
  1446.  
  1447.     HANDLES rgHandles[] = 
  1448.     {
  1449.         SQL_HANDLE_ENV, henv,
  1450.         SQL_HANDLE_DBC, hdbc,
  1451.         SQL_HANDLE_STMT, hstmt,
  1452.         SQL_HANDLE_DESC, hdesc,
  1453.     };
  1454.  
  1455.     cHandles=sizeof(rgHandles)/sizeof(HANDLES);
  1456.  
  1457.     /* Call SQLGetInfo to get values to compare: */
  1458.     rcFunction = SQLGetInfo(hdbc, SQL_DATA_SOURCE_NAME, szDataSourceName, MAX_STRING_SIZE, NULL);
  1459.     RETCHECK(SQL_SUCCESS, rcFunction, szSQLGETINFO);
  1460.  
  1461.     /* Allocate an hdesc: */
  1462.     if(Supported(SQL_API_SQLALLOCHANDLE) && g_f3XDriver)
  1463.     { 
  1464.         rcFunction = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc);
  1465.         RETCHECK(SQL_SUCCESS, rcFunction, szSQLALLOCHANDLE);
  1466.  
  1467.         // Update the array entry for the hdesc
  1468.         rgHandles[3].hHandle=hdesc;
  1469.  
  1470.     }
  1471.     else
  1472.         cHandles--;
  1473.  
  1474.     for (iHandle=0; iHandle < cHandles; iHandle++)
  1475.     {
  1476.  
  1477.         SetErrorCondition(rgHandles[iHandle].fHandleType);
  1478.  
  1479.         rc = SQLGetDiagRec(rgHandles[iHandle].fHandleType, rgHandles[iHandle].hHandle, 
  1480.                     1,szState,&fNativeError, szErrorMsg,
  1481.                     SQL_MAX_MESSAGE_LENGTH, &cbErrorMsg);
  1482.  
  1483.         if (rgHandles[iHandle].fHandleType == SQL_HANDLE_DESC)
  1484.             pszExpState=szHY091;
  1485.  
  1486.         rcExp=SQL_SUCCESS;
  1487.  
  1488.         if(fDiagRecSupported)
  1489.         {
  1490.  
  1491.             DIAGRETCHECK(rcExp, rc, szSQLGETDIAGREC);
  1492.             if (RC_SUCCESSFUL(rc) && lstrcmp(szState,pszExpState))
  1493.             {
  1494.                 wsprintf(szBuff,TEXT("\t\t\tReceived: %s\tExpected: %s"),szState,    pszExpState);
  1495.                 DISPLAYERROR(szSQLGETDIAGREC,szBuff);
  1496.             }
  1497.         }
  1498.         else
  1499.         {
  1500.             if(!FindError(rgHandles[iHandle].fHandleType, szIM001))
  1501.                 DISPLAYERROR(szSQLGETDIAGREC, szNotSupported);
  1502.         }
  1503.  
  1504.     }
  1505.  
  1506.  
  1507.     /* Free the hdesc: */
  1508.     if (hdesc)
  1509.     {
  1510.         rcFunction = SQLFreeHandle(SQL_HANDLE_DESC, hdesc);
  1511.         RETCHECK(rcExp, rcFunction, szSQLFREEHANDLE);
  1512.         hdesc = SQL_NULL_HDESC;
  1513.     }
  1514.  
  1515. //ExitTestDiagRec
  1516.  
  1517.     FreeStmt(SQL_CLOSE);
  1518.  
  1519. } /* TestDiagRec() */
  1520.  
  1521.  
  1522. /*------------------------------------------------------------------------------
  1523. /    Function:    TestDiagField                                                       
  1524. /    Purpose:    For each type of handle, generate an error. If SQLGetDiagField      
  1525. /                is not supported, verify the appropriate DM error is returned.      
  1526. /                Otherwise, verify SQLGetDiagField returns the expected error        
  1527. /                information. If SQLGetDiagRec is not supported, verify the          
  1528. /                appropriate DM error is returned. Otherwise, verify                 
  1529. /                SQLGetDiagField returns the expected error information. If          
  1530. /                SQLGetDiagRec is supported, compare its output with that of         
  1531. /                SQLGetDiagField.                                                    
  1532. /*----------------------------------------------------------------------------*/
  1533.  
  1534. void PASCAL TestDiagField()
  1535. {
  1536.     SQLRETURN    rcFunction, 
  1537.                     rc=SQL_SUCCESS;
  1538.     SWORD            cbValue=0;
  1539.     UWORD            iHandle=0,
  1540.                     iField=0,
  1541.                     cHandles;
  1542.  
  1543.     TCHAR            szDataSourceName[MAX_STRING_SIZE] = TEXT("");
  1544.     TCHAR            rgbValue[SQL_MAX_MESSAGE_LENGTH];
  1545.     TCHAR            szAPI[MEDBUFF]=TEXT("");
  1546.     TCHAR            szBuff[MEDBUFF]=TEXT("");
  1547.     RETCODE        rcExp=SQL_SUCCESS;
  1548.  
  1549.     HANDLES rgHandles[] = 
  1550.     {
  1551.         SQL_HANDLE_ENV, henv,
  1552.         SQL_HANDLE_DBC, hdbc,
  1553.         SQL_HANDLE_STMT, hstmt,
  1554.         SQL_HANDLE_DESC, hdesc,
  1555.     };
  1556.  
  1557.     cHandles=sizeof(rgHandles)/sizeof(HANDLES);
  1558.  
  1559.     /* Call SQLGetInfo to get values to compare: */
  1560.     rcFunction = SQLGetInfo(hdbc, SQL_DATA_SOURCE_NAME, szDataSourceName, MAX_STRING_SIZE, NULL);
  1561.     RETCHECK(SQL_SUCCESS, rcFunction, szSQLGETINFO);
  1562.  
  1563.     hdesc = SQL_NULL_HDESC;
  1564.  
  1565.     /* Allocate an hdesc: */
  1566.     if(Supported(SQL_API_SQLALLOCHANDLE) && g_f3XDriver)
  1567.     { 
  1568.         rcFunction = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc);
  1569.         RETCHECK(SQL_SUCCESS, rcFunction, szSQLALLOCHANDLE);
  1570.  
  1571.         // Update the array entry for the hdesc
  1572.         rgHandles[3].hHandle=hdesc;
  1573.  
  1574.     }
  1575.     else
  1576.         cHandles--;
  1577.  
  1578.     for (iHandle=0; iHandle < cHandles; iHandle++)
  1579.     {
  1580.  
  1581.         SetErrorCondition(rgHandles[iHandle].fHandleType);
  1582.  
  1583.         if(fDiagFieldSupported)
  1584.         {
  1585.             for (iField=0;iField < sizeof(rgDiagInfo)/sizeof(struct tagDIAGINFO);iField++)
  1586.             {
  1587.                 rc = SQLGetDiagField(rgHandles[iHandle].fHandleType, rgHandles[iHandle].hHandle, 
  1588.                             rgDiagInfo[iField].irecRecNumber, rgDiagInfo[iField].uwDescField,
  1589.                             rgbValue, SQL_MAX_MESSAGE_LENGTH, &cbValue);
  1590.     
  1591.                 DIAGRETCHECK(rcExp, rc, szSQLGETDIAGFIELD);
  1592.  
  1593.                 if (RC_SUCCESSFUL(rc))
  1594.                     CheckData(rgHandles[iHandle].fHandleType,rgDiagInfo[iField].uwDescField, 
  1595.                         rgbValue,szDataSourceName);
  1596.             }
  1597.             
  1598.         }
  1599.         else
  1600.         {
  1601.             rc = SQLGetDiagField(SQL_HANDLE_ENV, henv, 0, SQL_DIAG_RETURNCODE, rgbValue,SQL_MAX_MESSAGE_LENGTH, &cbValue);
  1602.  
  1603.             if(!FindError(rgHandles[iHandle].fHandleType, szIM001))
  1604.                 DISPLAYERROR(szAPI, szNotSupported);
  1605.                 
  1606.         }
  1607.  
  1608.     }
  1609.  
  1610.  
  1611.     /* Free the hdesc: */
  1612.     if (hdesc)
  1613.     {
  1614.         rcFunction = SQLFreeHandle(SQL_HANDLE_DESC, hdesc);
  1615.         RETCHECK(rcExp, rcFunction, szSQLFREEHANDLE);
  1616.         hdesc = SQL_NULL_HDESC;
  1617.     }
  1618.  
  1619. //ExitTestDiagField
  1620.  
  1621.     FreeStmt(SQL_CLOSE);
  1622.  
  1623. } /* TestDiagField() */
  1624.  
  1625. //------------------------------------------------------------------------------
  1626. //    Function:    CompareAnsiToUnicode
  1627. //        Compares an ANSI string to a Unicode string
  1628. //------------------------------------------------------------------------------
  1629. BOOL CompareAnsiToUnicode(SQLCHAR * aszBuf, SQLINTEGER cbA, SQLWCHAR * wszBuf,
  1630.     SQLINTEGER cbW, SQLTCHAR * szAPI)
  1631. {
  1632.     SQLCHAR aszConvBuf[MAX_STRING_SIZE];
  1633.     SQLINTEGER cbT;
  1634.     BOOL bCompare=TRUE;
  1635.  
  1636.     // Check ANSI count of bytes returned
  1637.     if ((cbA != SQL_NULL_DATA) && (SQLINTEGER)strlen(aszBuf) != cbA)
  1638.     {
  1639.         wsprintf(buf, TEXT("ANSI count of bytes returned incorrect.")\
  1640.             TEXT(" Expected: %d, received: %d"),
  1641.             strlen(aszBuf), cbA);
  1642.         DISPLAYERROR(szAPI, buf);
  1643.         bCompare=FALSE;
  1644.     }
  1645.  
  1646.     // Compare ANSI count of bytes with Unicode count
  1647.     cbT = (cbA > 0) ? (SQLINTEGER)(cbA * sizeof(SQLWCHAR)) : cbA;
  1648.     if (cbW != cbT)
  1649.     {
  1650.         wsprintf(buf, TEXT("Unicode count of bytes returned incorrect.")\
  1651.             TEXT(" Expected: %d, received: %d"), cbT, cbW);
  1652.         DISPLAYERROR(szAPI, buf);
  1653.         bCompare=FALSE;
  1654.     }
  1655.  
  1656.     // Compare strings if not NULL DATA
  1657.     if (cbA != SQL_NULL_DATA)
  1658.     {
  1659.         // Compare ANSI and Unicode strings returned
  1660.         (void)(WideCharToMultiByte(CP_ACP, 0, wszBuf, wcslen(wszBuf), aszConvBuf,
  1661.             sizeof(aszConvBuf), NULL, NULL));
  1662.         aszConvBuf[wcslen(wszBuf)]=TEXT('\0');
  1663.  
  1664.         if (strcmp(aszBuf, aszConvBuf))
  1665.         {
  1666.             wsprintf(buf, TEXT("Unicode string did not match ANSI string.\r\n")\
  1667.                 TEXT("\t\t\tExpected: '%hs', Received: '%hs'"), aszBuf, aszConvBuf);
  1668.             DISPLAYERROR(szAPI, buf);
  1669.             bCompare=FALSE;
  1670.         }
  1671.     }
  1672.  
  1673.     return bCompare;
  1674. }
  1675.  
  1676. //------------------------------------------------------------------------------
  1677. //    Function:    CompareAnsiUnicodeResults
  1678. //        Compares an ANSI result set to a Unicode result set
  1679. //------------------------------------------------------------------------------
  1680. void CompareAnsiUnicodeResults(SQLHSTMT hstmtA, SQLHSTMT hstmtW, SQLTCHAR * szAPI)
  1681. {
  1682.     SQLCHAR aszBuf[MAX_STRING_SIZE];
  1683.     SQLWCHAR wszBuf[MAX_STRING_SIZE];
  1684.     SQLINTEGER cbANSI, cbUnicode;
  1685.     SQLUSMALLINT    uwCol;
  1686.     SQLSMALLINT        swColCountA, swColCountW;
  1687.     SQLRETURN rc, rcA, rcW;
  1688.  
  1689.     // Check width of result sets
  1690.     rc=SQLNumResultCols(hstmtA, &swColCountA);
  1691.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtA, SQL_SUCCESS, rc, szSQLNUMRESULTCOLS);
  1692.     rc=SQLNumResultCols(hstmtW, &swColCountW);
  1693.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_SUCCESS, rc, szSQLNUMRESULTCOLS);
  1694.     if (swColCountA != swColCountW)
  1695.         DISPLAYERROR(szAPI,TEXT("ANSI and Unicode result sets different widths."));
  1696.  
  1697.     uwCol=1;
  1698.     do {
  1699.         rc=SQLBindCol(hstmtA, uwCol, SQL_C_CHAR, aszBuf, sizeof(aszBuf), &cbANSI);
  1700.         ERRSHANDLE(SQL_HANDLE_STMT, hstmtA, SQL_SUCCESS, rc, szSQLBINDCOL);
  1701.         rc=SQLBindCol(hstmtW, uwCol, SQL_C_WCHAR, wszBuf, sizeof(wszBuf), &cbUnicode);
  1702.         ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_SUCCESS, rc, szSQLBINDCOL);
  1703.  
  1704.         // Copy something into the buffers so we can tell if they were modified
  1705.         strcpy(aszBuf, "Untouched");
  1706.         wcscpy(wszBuf, L"Untouched");
  1707.  
  1708.         // Fetch into the buffers
  1709.         rcA=SQLFetch(hstmtA);
  1710.         rcW=SQLFetch(hstmtW);
  1711.  
  1712.  
  1713.         if (RC_SUCCESSFUL(rcA) && RC_SUCCESSFUL(rcW))
  1714.         {
  1715.             if (!CompareAnsiToUnicode(aszBuf, cbANSI, wszBuf, cbUnicode, szSQLFETCH))
  1716.             {
  1717.                 rcW=SQL_NO_DATA;    // Abort the loop w/o generating failure
  1718.                 rcA=SQL_NO_DATA;
  1719.             }
  1720.         }
  1721.  
  1722.         // Unbind the column bound above on each statement
  1723.         rc=SQLFreeStmt(hstmtA, SQL_UNBIND);
  1724.         ERRSHANDLE(SQL_HANDLE_STMT, hstmtA, SQL_SUCCESS, rc, szSQLFREESTMT);
  1725.         rc=SQLFreeStmt(hstmtW, SQL_UNBIND);
  1726.         ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_SUCCESS, rc, szSQLFREESTMT);
  1727.  
  1728.         // Don't exceed the total number of columns in result set
  1729.         uwCol++;
  1730.         if (uwCol > (SQLUSMALLINT)swColCountA)
  1731.             uwCol=1;
  1732.     }
  1733.     while (RC_SUCCESSFUL(rcA) && RC_SUCCESSFUL(rcW));
  1734.  
  1735.     // Make sure the result sets were the same size
  1736.     if (rcW != SQL_NO_DATA)
  1737.         ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_NO_DATA, rc, szSQLFETCH);
  1738.  
  1739.     // Make sure the result sets were the same size
  1740.     if (rcA != rcW)
  1741.         DISPLAYERROR(szAPI,TEXT("ANSI and Unicode result sets not the same length."));
  1742.  
  1743.     rc=SQLFreeStmt(hstmtA, SQL_CLOSE);
  1744.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtA, SQL_SUCCESS, rc, szSQLFREESTMT);
  1745.     rc=SQLFreeStmt(hstmtW, SQL_CLOSE);
  1746.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_SUCCESS, rc, szSQLFREESTMT);
  1747.  
  1748. }
  1749.  
  1750.  
  1751. /*------------------------------------------------------------------------------
  1752. /    Function:    TestMixedAnsiUnicode
  1753. /    Purpose:    Call several of the Unicode functions mixed with ANSI functions
  1754. /                to verify functions succeed in the mixed case.
  1755. /*----------------------------------------------------------------------------*/
  1756. void PASCAL TestMixedAnsiUnicode(QTSTRUCT * lpqt)
  1757. {
  1758.     HDBC    hdbcANSI, hdbcUnicode;
  1759.     HSTMT hstmtANSIA, hstmtANSIW, hstmtUA, hstmtUW, hstmtW;
  1760.     SQLINTEGER cbANSI, cbUnicode;
  1761.     SQLWCHAR wszServer[MAX_STRING_SIZE], wszLogin[MAX_STRING_SIZE],
  1762.         wszPassword[MAX_STRING_SIZE], wszQuery[MAX_STRING_SIZE],
  1763.         wszBuf[MAX_STRING_SIZE], wszTable[MAX_STRING_SIZE];
  1764.     SQLCHAR    aszServer[MAX_STRING_SIZE], aszLogin[MAX_STRING_SIZE],
  1765.         aszPassword[MAX_STRING_SIZE], aszQuery[MAX_STRING_SIZE],
  1766.         aszBuf[MAX_STRING_SIZE], aszTable[MAX_STRING_SIZE];
  1767.     SQLUSMALLINT fStmts;
  1768.     SQLRETURN rc, rcA=SQL_SUCCESS, rcW=SQL_SUCCESS;
  1769.     
  1770.     // We've already set the environment attribute to 3.0 by this point
  1771.     
  1772. #ifdef UNICODE
  1773.     // Copy the unicode strings
  1774.     lstrcpy(wszServer, lpSI->szValidServer0);
  1775.     lstrcpy(wszLogin, lpSI->szValidLogin0);
  1776.     lstrcpy(wszPassword, lpSI->szValidPassword0);
  1777.     lstrcpy(wszTable, lpqt->szTableName);
  1778.     wsprintf(wszQuery,szSELECTSTAR,lpqt->szTableName);
  1779.  
  1780.     // Convert and copy to ANSI strings
  1781.     /*
  1782.     int WideCharToMultiByte(
  1783.          UINT  CodePage,    // code page 
  1784.          DWORD  dwFlags,    // performance and mapping flags 
  1785.          LPCWSTR  lpWideCharStr,    // address of wide-character string 
  1786.          int  cchWideChar,    // number of characters in string 
  1787.          LPSTR  lpMultiByteStr,    // address of buffer for new string 
  1788.          int  cchMultiByte,    // size of buffer 
  1789.          LPCSTR  lpDefaultChar,    // address of default for unmappable characters  
  1790.          LPBOOL  lpUsedDefaultChar     // address of flag set when default char. used 
  1791.         );    
  1792.     */
  1793.     // Server
  1794.     (void)(WideCharToMultiByte(CP_ACP,
  1795.                           0,
  1796.                           lpSI->szValidServer0,
  1797.                           lstrlen(lpSI->szValidServer0),
  1798.                           aszServer,
  1799.                           sizeof(aszServer),
  1800.                           NULL,
  1801.                           NULL));
  1802.     aszServer[lstrlen(lpSI->szValidServer0)]=TEXT('\0');
  1803.  
  1804.     // UID
  1805.     (void)(WideCharToMultiByte(CP_ACP,
  1806.                           0,
  1807.                           lpSI->szValidLogin0,
  1808.                           lstrlen(lpSI->szValidLogin0),
  1809.                           aszLogin,
  1810.                           sizeof(aszLogin),
  1811.                           NULL,
  1812.                           NULL));
  1813.     aszLogin[lstrlen(lpSI->szValidLogin0)]=TEXT('\0');
  1814.  
  1815.     // PWD
  1816.     (void)(WideCharToMultiByte(CP_ACP,
  1817.                           0,
  1818.                           lpSI->szValidPassword0,
  1819.                           lstrlen(lpSI->szValidPassword0),
  1820.                           aszPassword,
  1821.                           sizeof(aszPassword),
  1822.                           NULL,
  1823.                           NULL));
  1824.     aszPassword[lstrlen(lpSI->szValidPassword0)]=TEXT('\0');
  1825.  
  1826.     // Select stmt
  1827.     (void)(WideCharToMultiByte(CP_ACP,
  1828.                           0,
  1829.                           wszQuery,
  1830.                           lstrlen(wszQuery),
  1831.                           aszQuery,
  1832.                           sizeof(aszQuery),
  1833.                           NULL,
  1834.                           NULL));
  1835.     aszQuery[lstrlen(wszQuery)]=TEXT('\0');
  1836.  
  1837.     // Table name
  1838.     (void)(WideCharToMultiByte(CP_ACP,
  1839.                           0,
  1840.                           wszTable,
  1841.                           lstrlen(wszTable),
  1842.                           aszQuery,
  1843.                           sizeof(aszTable),
  1844.                           NULL,
  1845.                           NULL));
  1846.     aszTable[lstrlen(wszTable)]=TEXT('\0');
  1847.  
  1848. #else
  1849.     // Copy the ANSI strings
  1850.     lstrcpy(aszServer, lpSI->szValidServer0);
  1851.     lstrcpy(aszLogin, lpSI->szValidLogin0);
  1852.     lstrcpy(aszPassword, lpSI->szValidPassword0);
  1853.     lstrcpy(aszTable, lpqt->szTableName);
  1854.     wsprintf(aszQuery,szSELECTSTAR,lpqt->szTableName);
  1855.  
  1856.     // Convert and copy to Unicode strings
  1857.     /*
  1858.     int MultiByteToWideChar(
  1859.          UINT  CodePage,    // code page 
  1860.          DWORD  dwFlags,    // character-type options 
  1861.          LPCSTR  lpMultiByteStr,    // address of string to map 
  1862.          int  cchMultiByte,    // number of characters in string 
  1863.          LPWSTR  lpWideCharStr,    // address of wide-character buffer 
  1864.          int  cchWideChar     // size of buffer 
  1865.         );    
  1866.     */
  1867.  
  1868.     // Server
  1869.     (void) MultiByteToWideChar(CP_ACP,
  1870.                                     0,
  1871.                                     lpSI->szValidServer0,
  1872.                                     lstrlen(lpSI->szValidServer0),
  1873.                                     wszServer,
  1874.                                     sizeof(wszServer)/sizeof(WCHAR)
  1875.                                     );
  1876.     wszServer[lstrlen(lpSI->szValidServer0)]=TEXT('\0');
  1877.  
  1878.     // UID
  1879.     (void) MultiByteToWideChar(CP_ACP,
  1880.                                     0,
  1881.                                     lpSI->szValidLogin0,
  1882.                                     lstrlen(lpSI->szValidLogin0),
  1883.                                     wszLogin,
  1884.                                     sizeof(wszLogin)/sizeof(WCHAR)
  1885.                                     );
  1886.     wszLogin[lstrlen(lpSI->szValidLogin0)]=TEXT('\0');
  1887.  
  1888.     // PWD
  1889.     (void) MultiByteToWideChar(CP_ACP,
  1890.                                     0,
  1891.                                     lpSI->szValidPassword0,
  1892.                                     lstrlen(lpSI->szValidPassword0),
  1893.                                     wszPassword,
  1894.                                     sizeof(wszPassword)/sizeof(WCHAR)
  1895.                                     );
  1896.     wszPassword[lstrlen(lpSI->szValidPassword0)]=TEXT('\0');
  1897.  
  1898.     // Select stmt
  1899.     (void) MultiByteToWideChar(CP_ACP,
  1900.                                     0,
  1901.                                     aszQuery,
  1902.                                     lstrlen(aszQuery),
  1903.                                     wszQuery,
  1904.                                     sizeof(wszQuery)/sizeof(WCHAR)
  1905.                                     );
  1906.     wszQuery[lstrlen(aszQuery)]=TEXT('\0');
  1907.  
  1908.     // Table name
  1909.     (void) MultiByteToWideChar(CP_ACP,
  1910.                                     0,
  1911.                                     aszTable,
  1912.                                     lstrlen(aszTable),
  1913.                                     wszTable,
  1914.                                     sizeof(wszTable)/sizeof(WCHAR)
  1915.                                     );
  1916.     wszTable[lstrlen(aszTable)]=TEXT('\0');
  1917.  
  1918. #endif
  1919.  
  1920.     // Allocate connection for ANSI
  1921.     rc = SQLAllocConnect(henv, &hdbcANSI);
  1922.     RETCHECK(SQL_SUCCESS, rc, szSQLALLOCCONNECT);
  1923.  
  1924.     // Allocate connection for Unicode
  1925.     rc = SQLAllocConnect(henv, &hdbcUnicode);
  1926.     RETCHECK(SQL_SUCCESS, rc, szSQLALLOCCONNECT);
  1927.  
  1928.     // If Unicode is defined, then strings need to be converted to ANSI
  1929.     // before calling SQLConnectA
  1930.     rc = SQLConnectA(hdbcANSI, (LPSTR)aszServer, SQL_NTS,
  1931.                         (LPSTR)aszLogin, SQL_NTS,
  1932.                         (LPSTR)aszPassword, SQL_NTS);
  1933.     if (!RC_SUCCESSFUL(rc))
  1934.         ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLCONNECT);
  1935.  
  1936.     rc = SQLConnectW(hdbcUnicode, (LPWSTR)wszServer, SQL_NTS,
  1937.                         (LPWSTR)wszLogin, SQL_NTS,
  1938.                         (LPWSTR)wszPassword, SQL_NTS);
  1939.     if (!RC_SUCCESSFUL(rc))
  1940.         ERRSHANDLE(SQL_HANDLE_DBC, hdbcUnicode, SQL_SUCCESS, rc,szSQLCONNECTW);
  1941.  
  1942.     // Test mixed SQLNativeSQL calls    on the ANSI connection
  1943.     rc=SQLNativeSqlA(hdbcANSI, aszQuery, strlen(aszQuery), aszBuf, sizeof(aszBuf), &cbANSI);
  1944.     ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLNATIVESQL);
  1945.     rc=SQLNativeSqlW(hdbcANSI,    wszQuery, wcslen(wszQuery)*sizeof(WCHAR), wszBuf, sizeof(wszBuf),
  1946.         &cbUnicode);
  1947.     ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLNATIVESQL);
  1948.  
  1949.     CompareAnsiToUnicode(aszBuf, cbANSI, wszBuf, cbUnicode, szSQLNATIVESQLW);
  1950.  
  1951.     // Allocate stmt handles for ANSI connection
  1952.     rc = SQLAllocStmt(hdbcANSI, &hstmtANSIA);    // Handle for ANSI calls
  1953.     ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLALLOCSTMT);
  1954.     rc = SQLAllocStmt(hdbcANSI, &hstmtANSIW);    // Handle for Unicode calls
  1955.     ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLALLOCSTMT);
  1956.  
  1957.     // Allocate stmt handles for Unicode connection
  1958.     rc = SQLAllocStmt(hdbcUnicode, &hstmtUA); // Handle for ANSI calls
  1959.     ERRSHANDLE(SQL_HANDLE_DBC, hdbcUnicode, SQL_SUCCESS, rc,szSQLALLOCSTMT);
  1960.     rc = SQLAllocStmt(hdbcUnicode, &hstmtUW); // Handle for Unicode calls
  1961.     ERRSHANDLE(SQL_HANDLE_DBC, hdbcUnicode, SQL_SUCCESS, rc,szSQLALLOCSTMT);
  1962.  
  1963.     // Call SQLTablesA&W on two different hdbcs
  1964.     strcpy(aszBuf,"%");
  1965.     wcscpy(wszBuf,L"%");
  1966.     rc = SQLTablesA(hstmtANSIA, NULL, 0, NULL, 0, aszBuf, SQL_NTS, NULL, 0);
  1967.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtANSIA, SQL_SUCCESS, rc, szSQLTABLESA);
  1968.     rc = SQLTablesW(hstmtUW, NULL, 0, NULL, 0, wszBuf, SQL_NTS, NULL, 0);
  1969.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtUW, SQL_SUCCESS, rc, szSQLTABLESW);
  1970.  
  1971.     // Compare the two result sets
  1972.     CompareAnsiUnicodeResults(hstmtANSIA, hstmtUW, szSQLTABLESW);
  1973.  
  1974.     // See if the driver supports multiple active stmts
  1975.     rc = SQLGetInfo(hdbcANSI, SQL_ACTIVE_STATEMENTS, &fStmts, 0, NULL);
  1976.     ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc, szSQLGETINFO);
  1977.  
  1978.     // Create a search string for ANSI
  1979.     aszBuf[0]=aszTable[0];
  1980.     aszBuf[1]=TEXT('\0');
  1981.     strcat(aszBuf,"%");
  1982.  
  1983.     // Create a search string for Unicode
  1984.     wszBuf[0]=wszTable[0];
  1985.     wszBuf[1]=TEXT('\0');
  1986.     wcscat(wszBuf,L"%");
  1987.  
  1988.     // If the allowed active statements is > 1, then use the same connection
  1989.     // otherwise use the other connection
  1990.     if (fStmts > 1)
  1991.         hstmtW=hstmtUW;
  1992.     else
  1993.         hstmtW=hstmtANSIW;
  1994.  
  1995.     // Call SQLColumnsA&W on two different hstmts (same connection if allowed)
  1996.     // Call for only the given table to limit compare errors at this time
  1997.     rc = SQLColumnsA(hstmtUA, NULL, 0, NULL, 0, aszTable, SQL_NTS, NULL, 0);
  1998.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtANSIA, SQL_SUCCESS, rc, szSQLCOLUMNSA);
  1999.     
  2000.     // Call for only the given table to limit compare errors at this time
  2001.     rc = SQLColumnsW(hstmtW, NULL, 0, NULL, 0, wszTable, SQL_NTS, NULL, 0);
  2002.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_SUCCESS, rc, szSQLCOLUMNSW);
  2003.  
  2004.     CompareAnsiUnicodeResults(hstmtUA, hstmtW, szSQLCOLUMNSW);
  2005.  
  2006.     rc = SQLExecDirectA(hstmtUA, aszQuery, SQL_NTS);
  2007.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtUA, SQL_SUCCESS, rc, szSQLEXECDIRECTA);
  2008.     
  2009.     // Call for only the given table to limit compare errors at this time
  2010.     rc = SQLExecDirectW(hstmtW, wszQuery, SQL_NTS);
  2011.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtW, SQL_SUCCESS, rc, szSQLEXECDIRECTW);
  2012.  
  2013.     CompareAnsiUnicodeResults(hstmtUA, hstmtW, szSQLEXECDIRECTW);
  2014.  
  2015.     // Disconnect and free ANSI handles
  2016.     rc=SQLFreeStmt(hstmtANSIA, SQL_DROP);
  2017.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtANSIA, SQL_SUCCESS, rc,szSQLFREESTMT);
  2018.     rc=SQLFreeStmt(hstmtANSIW, SQL_DROP);
  2019.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtANSIW, SQL_SUCCESS, rc,szSQLFREESTMT);
  2020.     rc=SQLDisconnect(hdbcANSI);
  2021.     ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLCONNECT);
  2022.     rc=SQLFreeConnect(hdbcANSI);
  2023.     ERRSHANDLE(SQL_HANDLE_DBC, hdbcANSI, SQL_SUCCESS, rc,szSQLCONNECT);
  2024.     // Disconnect and free Unicode handles
  2025.     rc=SQLFreeStmt(hstmtUA, SQL_DROP);
  2026.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtUA, SQL_SUCCESS, rc,szSQLFREESTMT);
  2027.     rc=SQLFreeStmt(hstmtUW, SQL_DROP);
  2028.     ERRSHANDLE(SQL_HANDLE_STMT, hstmtUW, SQL_SUCCESS, rc,szSQLFREESTMT);
  2029.     rc=SQLDisconnect(hdbcUnicode);
  2030.     ERRSHANDLE(SQL_HANDLE_DBC, hdbcUnicode, SQL_SUCCESS, rc,szSQLCONNECT);
  2031.     rc=SQLFreeConnect(hdbcUnicode);
  2032.     ERRSHANDLE(SQL_HANDLE_DBC, hdbcUnicode, SQL_SUCCESS, rc,szSQLCONNECT);
  2033.  
  2034. } /* TestMixedAnsiUnicode() */
  2035.  
  2036. //-----------------------------------------------------------------------
  2037. //      Function:               TestStmtOptions
  2038. //-----------------------------------------------------------------------
  2039.  
  2040. void  PASCAL TestStmtOptions()
  2041. {
  2042.     UDWORD    dwLen,
  2043.                 udw;
  2044.     BOOL        fConnectOption;
  2045.     RETCODE    rc=SQL_SUCCESS;
  2046.     TCHAR        szAPI[MEDBUFF];
  2047.     SDWORD    cbValue=0;
  2048.  
  2049.     SetStatementAttributes(SQL_MAX_LENGTH,(PTR)&udw);
  2050.  
  2051.     if (SetStatementAttributes(SQL_MAX_LENGTH, (PTR)TEST_STMT_OPTION))
  2052.         fConnectOption = TRUE;
  2053.  
  2054.     if (Supported(SQL_API_SQLGETSTMTATTR))
  2055.     {
  2056.         rc = SQLGetStmtAttr(hstmt, SQL_MAX_LENGTH, (PTR)&dwLen,sizeof(dwLen),&cbValue);
  2057.         lstrcpy(szAPI,szSQLGETSTMTATTR);
  2058.     }
  2059.     else
  2060.     {
  2061.         rc = SQLGetStmtOption(hstmt, SQL_MAX_LENGTH, &dwLen);
  2062.         lstrcpy(szAPI,szSQLGETSTMTOPTION);
  2063.     }
  2064.  
  2065.     if(rc != SQL_SUCCESS)
  2066.     {
  2067.         if(!FindError(SQL_HANDLE_STMT,szHYC00))
  2068.             RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTOPTION);
  2069.     }
  2070.     else
  2071.     {
  2072.         if(dwLen != TEST_STMT_OPTION && rc == SQL_SUCCESS && fConnectOption)
  2073.             DISPLAYERROR(szSQLGETSTMTOPTION,TEXT("incorrect SQL_MAX_LENGTH value returned"));
  2074.     }
  2075.  
  2076.  
  2077. } //TestStmtOptions()
  2078.  
  2079.  
  2080. //-----------------------------------------------------------------------
  2081. //      Function:               SetTableName
  2082. //-----------------------------------------------------------------------
  2083.  
  2084. void  PASCAL SetTableName(QTSTRUCT  *lpqt)
  2085. {
  2086.     RETCODE    rc=SQL_SUCCESS;
  2087.     UWORD        cTableName;
  2088.     TCHAR        szTime[MEDBUFF]=TEXT(""),
  2089.                 szTmpBuff[MEDBUFF],
  2090.                 *pTime=NULL;
  2091.  
  2092.     _tstrtime(szTmpBuff);
  2093.  
  2094.     /* Remove colons */
  2095.     pTime=_tcstok(szTmpBuff, TEXT(":"));
  2096.     while (pTime)
  2097.     {
  2098.         lstrcat(szTime,pTime);
  2099.         pTime=_tcstok(NULL, TEXT(":"));        
  2100.     }
  2101.      
  2102.     rc = SQLGetInfo(hdbc, SQL_MAX_TABLE_NAME_LEN, &cTableName,
  2103.         sizeof (int), NULL);
  2104.     if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
  2105.         RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO);
  2106.  
  2107.     rc = SQLGetInfo(hdbc, SQL_QUALIFIER_NAME_SEPARATOR, lpqt->buf,
  2108.         MAX_STRING_SIZE, NULL);
  2109.     if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
  2110.         RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO);
  2111.  
  2112.     if(!lstrcmp(TEXT("\\"), lpqt->buf))
  2113.         cTableName -= 4;
  2114.     
  2115.     _sntprintf(lpqt->szTableName, min(cTableName, MAX_TABLE_NAME-1),
  2116.                 TEXT("q%s"), szTime);
  2117.  
  2118. } //SetTableName()
  2119.  
  2120.  
  2121. //-----------------------------------------------------------------------
  2122. //      Function:               AllowedType
  2123. //
  2124. //        If swNumTypes > 0, limits SQL types to those in array
  2125. //-----------------------------------------------------------------------
  2126. BOOL AllowedType(SWORD fType)
  2127. {
  2128.     SWORD i, swNumTypes=0;
  2129.     BOOL bAllowed=TRUE;
  2130.     SWORD rgAllowedTypes[MAX_TYPES_SUPPORTED]={
  2131.         SQL_CHAR,
  2132.         SQL_BINARY
  2133. //        SQL_BIT
  2134. /*
  2135.         SQL_TINYINT
  2136.         SQL_NUMERIC,
  2137.         SQL_INTEGER,
  2138.         SQL_SMALLINT,
  2139.         SQL_FLOAT,
  2140.         SQL_REAL,
  2141.         SQL_TYPE_TIMESTAMP,
  2142.         SQL_LONGVARBINARY,
  2143.         SQL_LONGVARCHAR
  2144. */
  2145.     };
  2146.  
  2147.     if (swNumTypes > 0)
  2148.     {
  2149.         bAllowed=FALSE;
  2150.  
  2151.         for (i=0; i < swNumTypes; i++)
  2152.         {
  2153.             if (fType == rgAllowedTypes[i])
  2154.                 bAllowed=TRUE;
  2155.         }
  2156.     }
  2157.  
  2158.     return bAllowed;
  2159. }
  2160.  
  2161. //-----------------------------------------------------------------------
  2162. //      Function:               GetTypeInfo
  2163. //-----------------------------------------------------------------------
  2164.  
  2165. UWORD  PASCAL GetTypeInfo(FIELDINFO  *rgFields,QTSTRUCT  *lpqt)
  2166. {
  2167.     RETCODE        rc=SQL_SUCCESS;
  2168.     UWORD       cFieldName;
  2169.     SDWORD      cMaxTypeSize, cMaxRowSize;
  2170.     UWORD       i,
  2171.                     cTypes=0;
  2172.     SDWORD      sdw;
  2173.     LPTSTR       pch=NULL;
  2174.     BOOL            fAutoInc=0;
  2175.  
  2176.     /* Get the type information to use in a create statement for a table */
  2177.  
  2178.     rc = SQLGetInfo(hdbc, SQL_MAX_COLUMN_NAME_LEN, &cFieldName,
  2179.         sizeof cFieldName, NULL);
  2180.     RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO);
  2181.  
  2182.     rc = SQLGetInfo(hdbc, SQL_MAX_ROW_SIZE, &cMaxRowSize,
  2183.         sizeof cMaxRowSize, NULL);
  2184.     /* don't check for SQL_SUCCES here, it's a 2.0 function.  If it's successful
  2185.         That's great, if not then no maximum is assumed. */
  2186.     
  2187.     cMaxTypeSize = cMaxRowSize / MAX_TYPES_SUPPORTED;
  2188.     
  2189. /* TO DO: add checks in here for dos file types GetInfo SQL_QUALIFIER_NAME_SEPARATER */
  2190.  
  2191.     if(cFieldName > MAX_FIELD - 1)
  2192.         cFieldName = MAX_FIELD - 1;
  2193.  
  2194.     if(cFieldName < PREFIX_SIZE)
  2195.     {
  2196.         DISPLAYERROR(szSQLGETINFO,TEXT("MAX_COLUMN_NAME_LEN is too small for autotest to run"));
  2197.         goto TypeErrorRet;
  2198.     }
  2199.  
  2200.     rc = SQLGetTypeInfo(hstmt, SQL_ALL_TYPES);
  2201.     RETCHECK(SQL_SUCCESS, rc,szSQLGETTYPEINFO);
  2202.  
  2203.     for(i = 0; i < MAX_TYPES_SUPPORTED; i++)
  2204.     {
  2205.     
  2206.         rc = SQLFetch(hstmt);
  2207.         if(rc != SQL_SUCCESS && rc !=SQL_SUCCESS_WITH_INFO)
  2208.             break;
  2209.  
  2210.         *rgFields[i].szType = *rgFields[i].szLength = *rgFields[i].szParams = TEXT('\0');
  2211.  
  2212.         /* get type name */
  2213.         rc = SQLGetData(hstmt, 1, SQL_C_TCHAR,
  2214.             rgFields[i].szType, MAX_TYPE_NAME, &sdw);
  2215.  
  2216.         if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA))
  2217.             goto TypeErrorRet;
  2218.  
  2219.         wsprintf(rgFields[i].szFieldName,TEXT("c%02u"), i+COLNAME_START);
  2220.         /* copy first portion of type name for easy reference */
  2221.         _tcsnccat(rgFields[i].szFieldName, rgFields[i].szType, TYPE_PORTION);
  2222.  
  2223.  
  2224.         /* change spaces in field name to '_' */
  2225.         while((pch = (LPTSTR)_tcschr(rgFields[i].szFieldName, TEXT(' '))) != NULL)
  2226.             *pch = TEXT('_');
  2227.  
  2228.         /* get the SQLType */
  2229.         rc = SQLGetData(hstmt, 2, SQL_C_DEFAULT,
  2230.             (SWORD  *)&rgFields[i].wSQLType, IGNORED,
  2231.             &sdw);
  2232.         if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA))
  2233.             goto TypeErrorRet;
  2234.  
  2235.         /* Max length */
  2236.         rc = SQLGetData(hstmt, 3, SQL_C_TCHAR,
  2237.             rgFields[i].szLength, MAX_FIELD, &sdw);
  2238.         if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA))
  2239.             goto TypeErrorRet;
  2240.  
  2241.         /* limit the row size for those drivers that don't support a long
  2242.             enough row length for all the fields to be at the max length */
  2243.         switch(rgFields[i].wSQLType)
  2244.         {
  2245.             case SQL_CHAR:
  2246.             case SQL_VARCHAR:
  2247.             case SQL_VARBINARY:
  2248.             case SQL_BINARY:
  2249.             case SQL_LONGVARCHAR:
  2250.             case SQL_LONGVARBINARY:
  2251.  
  2252.                 if(cMaxTypeSize)
  2253.                 {
  2254.                     if(_ttol (rgFields[i].szLength) > cMaxTypeSize)
  2255.                         _ltot(cMaxTypeSize, rgFields[i].szLength, 10);
  2256.                 }
  2257.         }
  2258.  
  2259.         /* prefix */
  2260.         rc = SQLGetData(hstmt, 4, SQL_C_TCHAR,
  2261.             rgFields[i].szPrefix, MAX_PREFIX, &sdw);
  2262.         if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA))
  2263.             goto TypeErrorRet;
  2264.  
  2265.         /* suffix */
  2266.         rc = SQLGetData(hstmt, 5, SQL_C_TCHAR,
  2267.             rgFields[i].szSuffix, MAX_SUFFIX, &sdw);
  2268.         if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA))
  2269.             goto TypeErrorRet;
  2270.  
  2271.         /* create params */
  2272.         rc = SQLGetData(hstmt, 6, SQL_C_TCHAR,
  2273.             rgFields[i].szParams, MAX_PARAM_SIZE, &sdw);
  2274.         if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA))
  2275.             goto TypeErrorRet;
  2276.  
  2277.         /* nullable */
  2278.         rc = SQLGetData(hstmt, 7, SQL_C_SHORT, &rgFields[i].nullable, IGNORED,
  2279.             &sdw);
  2280.         if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA))
  2281.             goto TypeErrorRet;
  2282.  
  2283.         /* searchable */
  2284.         rc = SQLGetData(hstmt, 9, SQL_C_SHORT, &rgFields[i].fSearchable, IGNORED,
  2285.             &sdw);
  2286.         if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA))
  2287.             goto TypeErrorRet;
  2288.  
  2289.         /* autoincrement */
  2290.         rc = SQLGetData(hstmt, 12, SQL_C_SHORT, &rgFields[i].autoinc, IGNORED,
  2291.             &sdw);
  2292.         if(!RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA))
  2293.             goto TypeErrorRet;
  2294.  
  2295.         // Since some data types will have NULL for autoincrement, we need to set to FALSE
  2296.         if (SQL_NULL_DATA == sdw)
  2297.             rgFields[i].autoinc=FALSE;
  2298.  
  2299.         if (IgnoreType(rgFields[i].szType,rgFields[i].wSQLType))
  2300.         {
  2301.             i--;
  2302.             continue;
  2303.         }
  2304.  
  2305.         /* The following code only allows the first autoincrement column to
  2306.             be placed in the table.  Many DBMS's do not allow more than one per table. */
  2307.         if(rgFields[i].autoinc == TRUE)
  2308.         {
  2309.             if(fAutoInc)
  2310.             {
  2311.                 i--;
  2312.                 continue;
  2313.             }
  2314.             else
  2315.                 fAutoInc = TRUE;
  2316.         }
  2317.  
  2318.         // Limit data types to those desired (use for debugging)
  2319.         if (!AllowedType(rgFields[i].wSQLType))
  2320.         {
  2321.             i--;
  2322.             continue;
  2323.         }
  2324.     }
  2325.  
  2326.     cTypes = i;
  2327.  
  2328.     /* if the type name contains spaces, replace them with _ because
  2329.         most servers don't allow spaces in field names */
  2330.  
  2331.     RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH);
  2332.  
  2333.     rc = SQLFreeStmt(hstmt, SQL_CLOSE);
  2334.     RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT);
  2335.  
  2336.     SetTableName(lpqt);
  2337.  
  2338.     return(cTypes);
  2339.  
  2340. TypeErrorRet:
  2341.  
  2342.     return(0);
  2343.  
  2344. } //GetTypeInfo()
  2345.  
  2346.  
  2347.  
  2348.  
  2349. //-----------------------------------------------------------------------
  2350. //      Function:               BuildCreateStmt
  2351. //-----------------------------------------------------------------------
  2352.  
  2353. BOOL  PASCAL BuildCreateStmt(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes)
  2354. {
  2355.     RETCODE        rc=SQL_SUCCESS;
  2356.     TCHAR        szNum[MAX_NUM_BUFFER];   /* used with _ttoi and itoa conversions */
  2357.     SWORD       wNum;
  2358.     UWORD       i;
  2359.     SDWORD      sdw;
  2360.     LPTSTR       pch=NULL;
  2361.  
  2362.  
  2363.     /* the column names will be ctypname (where typename is the
  2364.         type name returned by the source in SQLGetTypeInfo) */
  2365.  
  2366.     *lpqt->sz = TEXT('\0');
  2367.     lstrcpy(lpqt->sz,TEXT("Create Table "));
  2368.     lstrcat(lpqt->sz, lpqt->szTableName);
  2369.     lstrcat(lpqt->sz,TEXT(" ("));
  2370.     for(i = 0; i < cTypes; i++) {
  2371.             TCHAR szParamType[50];
  2372.             TCHAR szNotNull[10];
  2373.             *lpqt->szParam = TEXT('\0');
  2374.  
  2375.         /* if SQLGetTypeInfo returned params they need to be used in
  2376.             the create statement */
  2377.         
  2378.         if(rgFields[i].szParams == NULL || lstrlen(rgFields[i].szParams) == 0)
  2379.             *lpqt->szParam = TEXT('\0');
  2380.         else if(_tcschr(rgFields[i].szParams, TEXT(',')) == NULL)
  2381.             wsprintf(lpqt->szParam,TEXT("(%s)"), rgFields[i].szLength);
  2382.         else
  2383.             {
  2384.             lstrcpy(szNum, rgFields[i].szLength);
  2385.             wsprintf(lpqt->szParam,TEXT("(%s, %d)"), rgFields[i].szLength,
  2386.                 _ttoi(szNum) - SCALEDIFF);
  2387.             }
  2388.  
  2389.         lstrcpy(szParamType, rgFields[i].szType);
  2390.         if(pch = _tcschr((LPTSTR)szParamType, TEXT('('))) 
  2391.             {
  2392.             *pch = TEXT('\0');
  2393.             lstrcat(szParamType, lpqt->szParam);
  2394.             lstrcat(szParamType, (LPTSTR)_tcschr(rgFields[i].szType, TEXT(')')) + 1);
  2395.             }
  2396.         else
  2397.             {
  2398.             lstrcat(szParamType, lpqt->szParam);
  2399.             }
  2400.  
  2401.         /* If the field is not nullable, we need to create the table that way */
  2402.         rc = SQLGetInfo(hdbc, SQL_NON_NULLABLE_COLUMNS, &wNum,
  2403.             sizeof (SWORD), NULL);
  2404.         if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
  2405.             RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO);
  2406.         
  2407.         if((rgFields[i].nullable == SQL_NO_NULLS) && (wNum != SQL_NNC_NULL))
  2408.             lstrcpy(szNotNull,TEXT("NOT NULL"));
  2409.         else
  2410.             szNotNull[0] = TEXT('\0');
  2411.         
  2412.         wsprintf(&lpqt->sz[lstrlen(lpqt->sz)],TEXT(" %s %s %s ,"),
  2413.             rgFields[i].szFieldName, (LPTSTR)szParamType, (LPTSTR)szNotNull);
  2414.     }
  2415.  
  2416.     /* remove the last comma and space */
  2417.     lpqt->sz[lstrlen(lpqt->sz) - 2] = TEXT('\0');
  2418.     lstrcat(lpqt->sz,TEXT(")"));
  2419.  
  2420.     rc = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  2421.     if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
  2422.         if(!RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT))
  2423.             goto BuildErrorRet;
  2424.  
  2425.     /* now that table was created, call SQLColumns.  Both as
  2426.         a test and to get necessary information to insert data */
  2427.  
  2428.     rc = SQLColumns(hstmt, NULL, SQL_NTS, NULL, SQL_NTS,
  2429.         lpqt->szTableName, SQL_NTS, NULL, SQL_NTS);
  2430.     RETCHECK(SQL_SUCCESS, rc,szSQLCOLUMNS);
  2431.  
  2432.     for(i = 0; i < cTypes; i++) {
  2433.         rc = SQLFetch(hstmt);
  2434.         RETCHECK(SQL_SUCCESS, rc,szSQLFETCH);
  2435.  
  2436.         /* precision */
  2437.         rc = SQLGetData(hstmt, 7, SQL_C_LONG, &rgFields[i].precision, IGNORED,
  2438.             &sdw);
  2439.         RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA);
  2440.  
  2441.         /* length */
  2442.         if((rgFields[i].precision == 0) || (sdw == SQL_NO_TOTAL)){
  2443.             rc = SQLGetData(hstmt, 8, SQL_C_LONG, &rgFields[i].precision, IGNORED,
  2444.                 &sdw);
  2445.             RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA);
  2446.             if(sdw == SQL_NO_TOTAL)        /* precision & length were undetermined */
  2447.                 rgFields[i].precision = 1000;    /* so set it to an arbitary value */
  2448.         }
  2449.  
  2450.         /* numeric scale */
  2451.         rc = SQLGetData(hstmt, 9, SQL_C_SHORT, &rgFields[i].scale, IGNORED,
  2452.             &sdw);
  2453.         RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA);
  2454.         if(sdw == SQL_NO_TOTAL)
  2455.             rgFields[i].scale = 0;
  2456.     }
  2457.  
  2458.     rc = SQLFreeStmt(hstmt, SQL_CLOSE);
  2459.     RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT);
  2460.  
  2461.     /* look for columns the test should not try to update by running
  2462.         a select * query and calling ColAttributes on the result fields */
  2463.     /* select * does not return the fields in a defined order, so field order
  2464.         must be specified */
  2465.  
  2466.     lstrcpy(lpqt->sz,TEXT("select "));
  2467.     for(i = 0; i < cTypes; i ++) {
  2468.         if(i)
  2469.             lstrcat(lpqt->sz,TEXT(","));
  2470.         lstrcat(lpqt->sz, rgFields[i].szFieldName);
  2471.     }
  2472.  
  2473.     lstrcat(lpqt->sz,TEXT(" from "));
  2474.     lstrcat(lpqt->sz, lpqt->szTableName);
  2475.  
  2476.     rc = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  2477.     RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  2478.  
  2479.     for(i = 1; i <= cTypes; i++) {
  2480.  
  2481.         rc = SQLColAttributes(hstmt, i, SQL_COLUMN_UPDATABLE, NULL,
  2482.             0, NULL, &sdw);
  2483.         RETCHECK(SQL_SUCCESS, rc,szSQLCOLATTRIBUTES);
  2484.  
  2485.         rgFields[i - 1].fAutoUpdate = sdw == SQL_ATTR_READONLY;
  2486.  
  2487.         rc = SQLColAttributes(hstmt, i, SQL_COLUMN_UNSIGNED, NULL,
  2488.             0, NULL, &sdw);
  2489.         RETCHECK(SQL_SUCCESS, rc,szSQLCOLATTRIBUTES);
  2490.  
  2491.         rgFields[i - 1].fUnsigned = sdw;
  2492.     }
  2493.  
  2494.     rc = SQLFreeStmt(hstmt, SQL_CLOSE);
  2495.     RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT);
  2496.  
  2497.     return(FALSE);
  2498.  
  2499. BuildErrorRet:
  2500.  
  2501.     return(TRUE);
  2502.  
  2503. } //BuildCreateStmt()
  2504.  
  2505.  
  2506.  
  2507. //-----------------------------------------------------------------------
  2508. //      Function:               BuildInsertStmt
  2509. //-----------------------------------------------------------------------
  2510.                                           
  2511. BOOL  PASCAL BuildInsertStmt(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes,
  2512.     DSTRUCT  *lpd,SDWORD  *cColsSelected,BOOL fBindParameter)
  2513. {
  2514.     RETCODE      rc;
  2515.     UWORD        w;
  2516.     UWORD        i;
  2517.     PTR            ptr;
  2518.     UWORD        ind;
  2519.     SDWORD       sdw;
  2520.     LPTSTR        pch=NULL;
  2521.     BOOL            fColNames=TRUE,
  2522.                     fLongData=FALSE;
  2523.     SDWORD          *sdwArray = (SDWORD  *)AllocateMemory(sizeof(SDWORD) * MAX_TYPES_SUPPORTED);
  2524.     
  2525.     lstrcpy(lpqt->szColNames,TEXT("\0"));
  2526.     lstrcpy(lpqt->szValues,TEXT("\0"));
  2527.     
  2528.     for(i = 0; i < cTypes; i++) {
  2529.  
  2530.         for(ind = 0, w = 0; ind < cTypes; ind++) {
  2531.  
  2532.             pch = qtMakeData(i, ind,&rgFields[ind], lpqt->szDataItem);
  2533.  
  2534.             if(!pch) /* current type is READ_ONLY) */
  2535.                 continue;
  2536.  
  2537.             /* for every nullable type, that field will be set to     */
  2538.             /* null when the row number corresponds with the field */
  2539.             /* number */
  2540.  
  2541.             if(*pch) 
  2542.                 {
  2543.                 lstrcpy(lpd[w].data, pch);
  2544.                 lpd[w].cb = SQL_NTS;
  2545.                 }
  2546.             else 
  2547.                 {
  2548.                 lstrcpy(lpd[w].data,TEXT(""));
  2549.                 lpd[w].cb = SQL_NULL_DATA;
  2550.                 }
  2551.  
  2552.             if(fColNames) 
  2553.                 {
  2554.                 /* the first time throught, the insert */
  2555.                 /* statement itself is created         */
  2556.                 lstrcat(lpqt->szColNames, rgFields[ind].szFieldName);
  2557.                 lstrcat(lpqt->szColNames,TEXT(", "));
  2558.                 lstrcat(lpqt->szValues,TEXT(" ?, "));
  2559.  
  2560.                 /* and parameters are set                                         */
  2561.                 /* set all the parameters using pointers to buffers in*/
  2562.                 /* the param struct.                                             */
  2563.                 if(!fBindParameter)
  2564.                     {
  2565.                     rc = SQLSetParam(hstmt, (UWORD)(w+1),
  2566.                         SQL_C_TCHAR, rgFields[ind].wSQLType,
  2567.                         rgFields[ind].precision, rgFields[ind].scale,
  2568.                         &lpd[w].data,
  2569.                         &lpd[w].cb);
  2570.                     RETCHECK(SQL_SUCCESS, rc,szSQLSETPARAM);
  2571.                     }
  2572.                 else
  2573.                     {
  2574.                     rc = SQLBindParameter(hstmt, (UWORD)(w+1),
  2575.                         SQL_PARAM_INPUT,
  2576.                         SQL_C_TCHAR, rgFields[ind].wSQLType,
  2577.                         rgFields[ind].precision, rgFields[ind].scale,
  2578.                         &lpd[w].data, MAX_STRING_SIZE,
  2579.                         &lpd[w].cb);
  2580.                     RETCHECK(SQL_SUCCESS, rc,szSQLBINDPARAMETER);
  2581.                     }
  2582.             }
  2583.             w++;
  2584.             cNumResSetCols=w;
  2585.         }
  2586.  
  2587.         if(fColNames) 
  2588.             { 
  2589.             /* the first time through, the insert            */
  2590.             /* statement needs to be SQLPrepare'd            */
  2591.             /* remove the "," at the end of the string    */
  2592.             lpqt->szColNames[lstrlen(lpqt->szColNames) - 2] = TEXT('\0');
  2593.             lpqt->szValues[lstrlen(lpqt->szValues) - 2] = TEXT('\0');
  2594.  
  2595.             wsprintf(lpqt->sz,TEXT("insert into %s (%s) VALUES(%s)"),
  2596.                 lpqt->szTableName, lpqt->szColNames, lpqt->szValues);
  2597.  
  2598.             //copy the insert statement, with the column names. 
  2599.             //_ASSERTE(lstrlen(lpqt->sz) < MAX_STRING_SIZE);
  2600.             lstrcpy(szInsertStmt,lpqt->sz);
  2601.  
  2602.             //prepare the statement
  2603.             rc = SQLPrepare(hstmt, lpqt->sz, SQL_NTS);
  2604.             if(!RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE))
  2605.                 goto InsertErrorRet;
  2606.  
  2607.             fColNames = FALSE; /* no more first times through */
  2608.             }
  2609.  
  2610.         rc = SQLExecute(hstmt); /* insert a row */
  2611.  
  2612.         if(!RETCHECK(SQL_SUCCESS, rc,szSQLEXECUTE))
  2613.         {
  2614.             if (SQL_SUCCESS_WITH_INFO != rc)        // BANDAID, normally would fail on S.W.I
  2615.                 goto InsertErrorRet;
  2616.         }
  2617.  
  2618.         rc = SQLRowCount(hstmt, &sdw);
  2619.         RETCHECK(SQL_SUCCESS, rc,szSQLROWCOUNT);
  2620.  
  2621.         if(sdw != 1) /* the execute inserted 1 row */
  2622.             DISPLAYERROR(szSQLROWCOUNT,TEXT("Insert single row"));
  2623.  
  2624.         /* FreeStmt SQL_CLOSE */
  2625.         rc = SQLFreeStmt(hstmt, SQL_CLOSE);
  2626.         RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT);
  2627.     }
  2628.  
  2629.     /* for the last row use SQLParamData and SQLPutData */
  2630.  
  2631.     /* First check to see if the SQL_LEN_DATA_AT_EXEC macro is supported */
  2632.     rc = SQLGetInfo(hdbc, SQL_NEED_LONG_DATA_LEN, lpqt->buf, (SWORD)sizeof(lpqt->buf), NULL);
  2633.     if(rc == SQL_SUCCESS)
  2634.         if(lpqt->buf[0] == TEXT('Y'))
  2635.             fLongData = TRUE;
  2636.     
  2637.     for(ind = 0, w = 0; ind < cTypes; ind++) 
  2638.         { 
  2639.  
  2640.         /* set all the params */
  2641.         
  2642.         if(rgFields[ind].fAutoUpdate)
  2643.             continue;
  2644.  
  2645.         if(fLongData && ((rgFields[ind].wSQLType == SQL_LONGVARBINARY) || 
  2646.             (rgFields[ind].wSQLType == SQL_LONGVARCHAR))){
  2647.             /* Make sure we don't exceed the max negative SDWORD value */
  2648.             if(rgFields[ind].precision > (MAXSDWORD + SQL_LEN_DATA_AT_EXEC_OFFSET))
  2649.                 sdwArray[ind] = MINSDWORD - SQL_LEN_DATA_AT_EXEC_OFFSET;
  2650.             else
  2651.                 sdwArray[ind] = SQL_LEN_DATA_AT_EXEC(rgFields[ind].precision);
  2652.             }
  2653.         else
  2654.             sdwArray[ind] = SQL_DATA_AT_EXEC;
  2655.  
  2656.         w++;
  2657.         if(!fBindParameter){
  2658.             rc = SQLSetParam(hstmt, w,
  2659.                 SQL_C_TCHAR, rgFields[ind].wSQLType,
  2660.                 rgFields[ind].precision, rgFields[ind].scale,
  2661.                 (LPTSTR)(UDWORD)ind, &sdwArray[ind]);
  2662.             RETCHECK(SQL_SUCCESS, rc,szSQLSETPARAM);
  2663.             }
  2664.         else{
  2665.             rc = SQLBindParameter(hstmt, w, SQL_PARAM_INPUT,
  2666.                 SQL_C_TCHAR, rgFields[ind].wSQLType,
  2667.                 rgFields[ind].precision, rgFields[ind].scale,
  2668.                 (LPTSTR)(((UDWORD)ind)+BIND_PARM_OFFSET), 0, &sdwArray[ind]);
  2669.             RETCHECK(SQL_SUCCESS, rc,szSQLBINDPARAMETER);
  2670.             }
  2671.     }
  2672.  
  2673.     *cColsSelected = w;
  2674.  
  2675.     rc = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  2676.     if (!RETCHECK(SQL_NEED_DATA, rc,szSQLEXECDIRECT))
  2677.         goto InsertErrorRet;
  2678.  
  2679.  
  2680.     for(ind = 0; ind <= cTypes; ind++) 
  2681.         {
  2682.         rc = SQLParamData(hstmt, &ptr);
  2683.         if(rc != SQL_NEED_DATA)
  2684.             break;
  2685.  
  2686.         pch = qtMakeData(cTypes, ind, &rgFields[(unsigned long)ptr-BIND_PARM_OFFSET],
  2687.             lpqt->szDataItem);
  2688.  
  2689.         if(*pch) {
  2690.             rc = SQLPutData(hstmt, pch, SQL_NTS);
  2691.             RETCHECK(SQL_SUCCESS, rc,szSQLPUTDATA);
  2692.         } else {
  2693.             rc = SQLPutData(hstmt, (LPTSTR)IGNORED, SQL_NULL_DATA);
  2694.             RETCHECK(SQL_SUCCESS, rc,szSQLPUTDATA);
  2695.         }
  2696.     }
  2697.                               
  2698.     RETCHECK(SQL_SUCCESS, rc,szSQLPARAMDATA);
  2699.  
  2700.     rc = SQLRowCount(hstmt, &sdw);
  2701.     RETCHECK(SQL_SUCCESS, rc,szSQLROWCOUNT);
  2702.  
  2703.     if(sdw != 1)
  2704.         DISPLAYERROR(szSQLROWCOUNT,TEXT("Insert single row"));
  2705.  
  2706.     rc = SQLFreeStmt(hstmt, SQL_RESET_PARAMS);
  2707.     RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT);
  2708.  
  2709.  
  2710.  
  2711.     ReleaseMemory(sdwArray);
  2712.  
  2713.     return(FALSE);
  2714.  
  2715. InsertErrorRet:
  2716.  
  2717.     ReleaseMemory(sdwArray);
  2718.  
  2719.     return(TRUE);
  2720.  
  2721. } //BuildInsertStmt()
  2722.  
  2723.  
  2724. //-----------------------------------------------------------------------
  2725. //      Function:               FullDisconnect
  2726. //-----------------------------------------------------------------------
  2727.  
  2728. void  PASCAL FullDisconnect()
  2729.     RETCODE rc=SQL_SUCCESS;
  2730.  
  2731.     /* SQLCancel has the same functionality as SQLFreeStmt w/ SQL_CLOSE    */
  2732.     /*    in a non-asynchronous environment                                             */
  2733.  
  2734.     rc = SQLCancel(hstmt);
  2735.     RETCHECK(SQL_SUCCESS, rc,szSQLCANCEL);
  2736.  
  2737.     FreeStmt(SQL_DROP);
  2738.  
  2739.     /* if the connection was made in the                        */
  2740.     /*    test, it should be disconnected                            */
  2741.     /* in the test, otherwise it should be left connected */
  2742.  
  2743.     rc = SQLDisconnect(hdbc);
  2744.     RETCHECK(SQL_SUCCESS, rc,szSQLDISCONNECT);
  2745.  
  2746.     rc = SQLFreeConnect(hdbc);
  2747.     RETCHECK(SQL_SUCCESS, rc,szSQLFREECONNECT);
  2748.  
  2749.     rc = SQLFreeEnv(henv);
  2750.     RETCHECK(SQL_SUCCESS, rc,szSQLFREEENV);
  2751.  
  2752.  
  2753. } //FullDisconnect()
  2754.  
  2755.  
  2756.  
  2757. //-----------------------------------------------------------------------
  2758. //      Function:               DropTable
  2759. //-----------------------------------------------------------------------
  2760.  
  2761. void  PASCAL DropTable(LPTSTR szTableName, BOOL fSilent)
  2762. {        
  2763.     TCHAR        szBuff[100];
  2764.     RETCODE    rc=SQL_ERROR;
  2765.  
  2766.     lstrcpy(szBuff,TEXT("drop table "));
  2767.     lstrcat(szBuff, szTableName);
  2768.  
  2769.     rc = SQLExecDirect(hstmt, szBuff, SQL_NTS);
  2770.  
  2771.     if (!fSilent)
  2772.         {
  2773.         if(!RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT))
  2774.             szWrite(TEXT("Unable to drop table"), TRUE);
  2775.         }
  2776.  
  2777. } //DropTable()
  2778.  
  2779.  
  2780.  
  2781. //-----------------------------------------------------------------------
  2782. //    Function:    CleanUp
  2783. //        Purpose:        To drop the table,disconnect from data source and
  2784. //                        release memory.            
  2785. //-----------------------------------------------------------------------
  2786.     
  2787. void  PASCAL CleanUp(DSTRUCT  *lpd,QTSTRUCT  *lpqt,FIELDINFO  *rgFields,
  2788.     LPTSTR szTableName,BOOL fSilent,LPTSTR szValidServer)
  2789. {
  2790.  
  2791.     DropTable(szTableName, fSilent);
  2792.  
  2793.     if(szValidServer)
  2794.         FullDisconnect();
  2795.  
  2796.     ReleaseMemory(lpd);
  2797.     ReleaseMemory(lpqt);
  2798.     ReleaseMemory(rgFields);
  2799.  
  2800. } //CleanUp()
  2801.  
  2802.  
  2803. //-----------------------------------------------------------------------
  2804. //      Function:               BindAllColumns
  2805. //-----------------------------------------------------------------------
  2806.  
  2807. BOOL  PASCAL BindAllColumns(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes,
  2808.     DSTRUCT  *lpd)
  2809. {
  2810. //-----------------------------------------------------------------------
  2811. //      Function:               BindAllColumns
  2812.     UWORD        i,
  2813.                 w;
  2814.     RETCODE    rc=SQL_SUCCESS;
  2815.  
  2816.     for(i = 0, w = 0; i < cTypes; i++) 
  2817.         {
  2818.  
  2819.         if(!qtMakeData(1, i,&rgFields[i],lpqt->szDataItem))
  2820.             continue;
  2821.  
  2822.         w++;
  2823.  
  2824.         switch(rgFields[i].wSQLType) 
  2825.             {
  2826.             case SQL_INTEGER:
  2827.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2828.                             &lpd[i].sdword, IGNORED, &lpd[i].cb);
  2829.                 break;
  2830.             case SQL_SMALLINT:
  2831.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2832.                             &lpd[i].sword, IGNORED, &lpd[i].cb);
  2833.                 break;
  2834.             case SQL_FLOAT:
  2835.             case SQL_DOUBLE:
  2836.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2837.                             &lpd[i].sdouble, IGNORED, &lpd[i].cb);
  2838.                 break;
  2839.             case SQL_REAL:
  2840.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2841.                             &lpd[i].sfloat, IGNORED, &lpd[i].cb);
  2842.                 break;
  2843.             case SQL_DATE:
  2844.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2845.                             &lpd[i].date, IGNORED, &lpd[i].cb);
  2846.                 break;
  2847.             case SQL_TIME:
  2848.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2849.                             &lpd[i].time, IGNORED, &lpd[i].cb);
  2850.                 break;
  2851.             case SQL_TIMESTAMP:
  2852.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2853.                             &lpd[i].timestamp, IGNORED, &lpd[i].cb);
  2854.                 break;
  2855.             case SQL_CHAR:
  2856.             case SQL_VARCHAR:
  2857.             case SQL_NUMERIC:
  2858.             case SQL_DECIMAL:
  2859.             default:
  2860.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2861.                             lpd[i].data, MAX_STRING_SIZE, &lpd[i].cb);
  2862.                 break;
  2863.             }
  2864.  
  2865.         if(!RETCHECK(SQL_SUCCESS, rc, szSQLBINDCOL))
  2866.             return(FALSE);
  2867.         }
  2868.  
  2869.     return(TRUE);
  2870.  
  2871. } //BindAllColumns()
  2872.  
  2873. /*-----------------------------------------------------------------------
  2874.  *      Function:               BindFetchColumns
  2875.  *  Used for Checking data in Result sets from fetch calls.
  2876.  *  Binds Binary data types as SQL_C_CHAR
  2877.  *----------------------------------------------------------------------- */
  2878.  
  2879. BOOL  PASCAL BindFetchColumns(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes,
  2880.     DSTRUCT  *lpdFetch)
  2881. {
  2882.     UWORD        i,
  2883.                 w;
  2884.     RETCODE    rc=SQL_SUCCESS;
  2885.  
  2886.     for(i = 0, w = 0; i < cTypes; i++) 
  2887.         {
  2888.  
  2889.         if(!qtMakeData(0, i,&rgFields[i],lpqt->szDataItem))
  2890.             continue;
  2891.  
  2892.         w++;
  2893.  
  2894.         switch(rgFields[i].wSQLType) 
  2895.             {
  2896.             case SQL_BIGINT:
  2897.             case SQL_INTEGER:
  2898.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2899.                             &lpdFetch[i].sdword, IGNORED, &lpdFetch[i].cb);
  2900.                 break;
  2901.             case SQL_TINYINT:
  2902.             case SQL_SMALLINT:
  2903.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2904.                             &lpdFetch[i].sword, IGNORED, &lpdFetch[i].cb);
  2905.                 break;
  2906.             case SQL_FLOAT:
  2907.             case SQL_DOUBLE:
  2908.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2909.                             &lpdFetch[i].sdouble, IGNORED, &lpdFetch[i].cb);
  2910.                 break;
  2911.             case SQL_REAL:
  2912.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2913.                             &lpdFetch[i].sfloat, IGNORED, &lpdFetch[i].cb);
  2914.                 break;
  2915.             case SQL_DATE:
  2916.             case SQL_TYPE_DATE:
  2917.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2918.                             &lpdFetch[i].date, IGNORED, &lpdFetch[i].cb);
  2919.                 break;
  2920.             case SQL_TIME:
  2921.             case SQL_TYPE_TIME:
  2922.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2923.                             &lpdFetch[i].time, IGNORED, &lpdFetch[i].cb);
  2924.                 break;
  2925.             case SQL_TIMESTAMP:
  2926.             case SQL_TYPE_TIMESTAMP:
  2927.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2928.                             &lpdFetch[i].timestamp, IGNORED, &lpdFetch[i].cb);
  2929.                 break;
  2930.             case SQL_BIT:
  2931.             case SQL_BINARY:
  2932.             case SQL_VARBINARY:
  2933.             case SQL_LONGVARBINARY:
  2934.                 rc = SQLBindCol(hstmt, w, SQL_C_TCHAR,
  2935.                             lpdFetch[i].data, MAX_STRING_SIZE, &lpdFetch[i].cb);
  2936.                 break;
  2937.             case SQL_CHAR:
  2938.             case SQL_VARCHAR:
  2939.             case SQL_NUMERIC:
  2940.             case SQL_DECIMAL:
  2941.             default:
  2942.                 rc = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  2943.                             lpdFetch[i].data, MAX_STRING_SIZE, &lpdFetch[i].cb);
  2944.                 break;
  2945.             }
  2946.  
  2947.         if(!RETCHECK(SQL_SUCCESS, rc, szSQLBINDCOL))
  2948.             return(FALSE);
  2949.         }
  2950.  
  2951.     return(TRUE);
  2952.  
  2953. } /*BindFetchColumns() */
  2954.  
  2955. //-----------------------------------------------------------------------
  2956. //      Function:               TestMetaData
  2957. //-----------------------------------------------------------------------
  2958.  
  2959. void  PASCAL TestMetaData(lpSERVERINFO lpSI, QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes)
  2960. {
  2961.     SWORD    wNum;
  2962.     UWORD    w;
  2963.     UWORD    i;
  2964.     UDWORD   dwLen;
  2965.     RETCODE    rc=SQL_SUCCESS;
  2966.     SWORD        wType;
  2967.     SWORD        wNull;
  2968.  
  2969.     SelectFromTable(lpqt);
  2970.  
  2971.     for(i = 0, w = 0; i < cTypes; i++) 
  2972.         {
  2973.         dwLen = 0;
  2974.         wNum = 0;
  2975.         wNull = 0;
  2976.  
  2977.         /* information returned by SQLDescribeCol should match info */
  2978.         /*    used to create table */
  2979.  
  2980.         if(!qtMakeData(1, i,&rgFields[i],lpqt->szDataItem))
  2981.             continue;
  2982.  
  2983.         w++;
  2984.         rc = SQLDescribeCol(hstmt, w, lpqt->buf,
  2985.             MAX_STRING_SIZE, NULL, &wType, &dwLen, &wNum, &wNull);
  2986.         RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBECOL);
  2987.  
  2988.         /* verify that column name returned is column name created */
  2989.  
  2990.         if(0 != lstrcmpi(rgFields[i].szFieldName, lpqt->buf))
  2991.             DISPLAYERROR(szSQLDESCRIBECOL,TEXT("incorrect column name"));
  2992.  
  2993.         if(wType != rgFields[i].wSQLType)
  2994.         {
  2995.             // For a 2.x driver, SQLGetTypeInfo result will be SQL_DATE, etc,
  2996.             // but 3.0 DM will convert SQLDescribeCol values to TYPE_DATE, ETC.
  2997.             if ((uDriverODBCVer < 3) && 
  2998.                 ((SQL_TYPE_DATE == wType && SQL_DATE == rgFields[i].wSQLType) ||
  2999.                 (SQL_TYPE_TIME == wType && SQL_TIME == rgFields[i].wSQLType) ||
  3000.                 (SQL_TYPE_TIMESTAMP == wType && SQL_TIMESTAMP == rgFields[i].wSQLType)))
  3001.                 NULL;
  3002.             else
  3003.                 DISPLAYERROR(szSQLDESCRIBECOL,TEXT("incorrect SQLType"));
  3004.         }
  3005.  
  3006.         if(dwLen != (UDWORD)rgFields[i].precision)
  3007.             DISPLAYERROR(szSQLDESCRIBECOL,TEXT("incorrect precision"));
  3008.         
  3009.         if(wNum != rgFields[i].scale)
  3010.             DISPLAYERROR(szSQLDESCRIBECOL,TEXT("incorrect scale"));
  3011.         
  3012.         if(wNull != rgFields[i].nullable && wNull != SQL_NULLABLE_UNKNOWN &&
  3013.             rgFields[i].nullable != SQL_NULLABLE_UNKNOWN)
  3014.             {
  3015.             DISPLAYERROR(szSQLDESCRIBECOL,TEXT("incorrect nullable"));
  3016.             }
  3017.         }
  3018.  
  3019.     FreeStmt(SQL_CLOSE);
  3020.  
  3021. } //TestMetaData()
  3022.  
  3023.  
  3024. //-----------------------------------------------------------------------
  3025. //      Function:               RetrieveData
  3026. //-----------------------------------------------------------------------
  3027.  
  3028. void PASCAL RetrieveData(QTSTRUCT *lpqt,FIELDINFO *rgFields,
  3029.     UWORD cTypes,DSTRUCT *lpd)
  3030. {
  3031.     RETCODE    rc=SQL_SUCCESS;
  3032.     UWORD        ind,
  3033.                 i;
  3034.     int        nSame;
  3035.     LPTSTR    pch=NULL;
  3036.     TCHAR        szNum[MAX_NUM_BUFFER];   /* used with _ttoi and itoa conversions */
  3037.     TCHAR        *stopstring=NULL;
  3038.     double    Num=0,
  3039.                 Num2=0;
  3040.  
  3041.     for(ind = 0; ;ind++) 
  3042.         {
  3043.  
  3044.         /* Get the data back */
  3045.         rc = SQLFetch(hstmt);
  3046.         if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
  3047.             break;
  3048.  
  3049.         for(i = 0; i < cTypes; i++) 
  3050.             { 
  3051.             /* make sure it's original data placed */
  3052.             /* in that field/row location             */
  3053.             pch = qtMakeData(ind, i,&rgFields[i], lpqt->szDataItem);
  3054.  
  3055.             if(!pch)
  3056.                 continue;
  3057.  
  3058.             if(!*pch) {
  3059.                 if(lpd[i].cb != SQL_NULL_DATA)
  3060.                     DISPLAYERROR(szRETDATA, TEXT("should have been NULL"));
  3061.                 continue;
  3062.             }
  3063.             switch(rgFields[i].wSQLType) 
  3064.                 {
  3065.                 /* check the outlen and data    */
  3066.                 /* returned for each type.     */
  3067.                 case SQL_INTEGER:
  3068.                     if(lpd[i].cb != sizeof(SDWORD))
  3069.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3070.  
  3071.                     lstrcpy(szNum, pch);
  3072.                     nSame = _ttol(szNum) == lpd[i].sdword;
  3073.                     break;
  3074.                 case SQL_SMALLINT:
  3075.                     if(lpd[i].cb != sizeof(SWORD))
  3076.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3077.  
  3078.                     lstrcpy(szNum, pch);
  3079.                     nSame = _ttoi(szNum) == lpd[i].sword;
  3080.                     break;
  3081.  
  3082.                 case SQL_FLOAT:
  3083.                 case SQL_DOUBLE:
  3084.                     if(lpd[i].cb != sizeof(SDOUBLE))
  3085.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3086.  
  3087.                     lstrcpy(szNum, pch);
  3088.                     Num=_tcstod(szNum, &stopstring);
  3089.                     nSame = Num - lpd[i].sdouble < 0.001 && Num - lpd[i].sdouble > -0.001;
  3090.  
  3091.                     break;
  3092.  
  3093.                 case SQL_REAL:
  3094.                     if(lpd[i].cb != sizeof(SFLOAT))
  3095.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3096.  
  3097.                     lstrcpy(szNum, pch);
  3098.                     Num=_tcstod(szNum, &stopstring);
  3099.  
  3100.                     nSame = Num - lpd[i].sfloat < 0.001 && Num - lpd[i].sfloat > -0.001;
  3101.                     break;
  3102.  
  3103.                 case SQL_TINYINT:
  3104.                     if(lpd[i].cb != sizeof(TCHAR))
  3105.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3106.  
  3107.                     lstrcpy(szNum, pch);
  3108.                     nSame = (TCHAR)_ttoi(szNum) == (TCHAR)lpd[i].data[0];
  3109.                     break;
  3110.  
  3111.                 case SQL_DECIMAL:
  3112.                 case SQL_NUMERIC:
  3113.                     if(lpd[i].cb > MAX_STRING_SIZE)
  3114.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3115.  
  3116.                     if(lpd[i].cb > lstrlen(lpd[i].data))
  3117.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3118.  
  3119.                     {
  3120.                     TCHAR szNum2[MAX_NUM_BUFFER];
  3121.  
  3122.                     lstrcpy(szNum, pch);
  3123.                     lstrcpy(szNum2, pch);
  3124.                     Num=_tcstod(szNum, &stopstring);
  3125.                     Num2=_tcstod(szNum2, &stopstring);
  3126.  
  3127.                     nSame = Num - Num2 < 0.001 &&    Num - Num2 > -0.001;
  3128.                     }
  3129.  
  3130.                     break;
  3131.  
  3132.  
  3133.                 case SQL_VARCHAR:
  3134.                 case SQL_LONGVARCHAR:
  3135.                     if(lpd[i].cb > MAX_STRING_SIZE)
  3136.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3137.  
  3138.                     if(lpd[i].cb > lstrlen(lpd[i].data))
  3139.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3140.  
  3141.                     nSame = !!_tcsstr(lpd[i].data, pch);
  3142.  
  3143.                     break;
  3144.  
  3145.                 case SQL_VARBINARY:
  3146.                 case SQL_LONGVARBINARY:
  3147.                     if(lpd[i].cb > MAX_STRING_SIZE)
  3148.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3149.  
  3150.                     if(lpd[i].cb  * 2 != lstrlen(pch))
  3151.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3152.  
  3153.                     nSame = TRUE; /* not checking returned data for binary */
  3154.  
  3155.                     break;
  3156.  
  3157.                 case SQL_CHAR:
  3158.                     if(lpd[i].cb > MAX_STRING_SIZE && rc == SQL_SUCCESS)
  3159.                         DISPLAYERROR(szRETDATA,TEXT("incorrect return code for outlen"));
  3160.  
  3161.                     if(lpd[i].cb != rgFields[i].precision && rc == SQL_SUCCESS)
  3162.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3163.  
  3164.                     nSame = !_tcsnccmp(lpd[i].data, pch, lstrlen(pch));
  3165.  
  3166.                     break;
  3167.                 case SQL_BINARY:
  3168.                 default:
  3169.                     if(lpd[i].cb > MAX_STRING_SIZE && rc == SQL_SUCCESS)
  3170.                         DISPLAYERROR(szRETDATA,szINCORRECTOUTLEN);
  3171.                     nSame = TRUE; /* not checking returned data for binary */
  3172.                 }
  3173.  
  3174.         if(!nSame)
  3175.             DISPLAYERROR(szRETDATA, TEXT("invalid data"));
  3176.         }
  3177.     }
  3178.  
  3179.     RETCHECK(SQL_NO_DATA_FOUND, rc, szSQLFETCH);
  3180.  
  3181.     if(ind != cTypes + 1)
  3182.         DISPLAYERROR(szSQLFETCH, TEXT("Incorrect number of result rows"));
  3183.  
  3184.     rc = SQLFreeStmt(hstmt, SQL_CLOSE);
  3185.     RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT);
  3186.  
  3187.     rc = SQLFreeStmt(hstmt, SQL_UNBIND);
  3188.     RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT);
  3189.  
  3190.     rc = SQLFreeStmt(hstmt, SQL_RESET_PARAMS);
  3191.     RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT);
  3192.  
  3193. } // RetrieveData()
  3194.  
  3195.  
  3196.                                       
  3197. //-----------------------------------------------------------------------
  3198. //      Function:               TestData
  3199. //-----------------------------------------------------------------------
  3200.  
  3201. void  PASCAL TestData(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,
  3202.     UWORD cTypes,DSTRUCT  *lpd)
  3203. {
  3204.  
  3205.     /* bind all fields to a variable of the correct type for retreiving data */
  3206.     if (!BindAllColumns(lpqt,rgFields,cTypes,lpd))
  3207.         return;
  3208.  
  3209.     SelectFromTable(lpqt);
  3210.  
  3211.     RetrieveData(lpqt,rgFields,cTypes,lpd);
  3212.  
  3213. } // TestData()
  3214.  
  3215.  
  3216. //-----------------------------------------------------------------------
  3217. //      Function:               CreateParamQuery
  3218. //-----------------------------------------------------------------------
  3219.  
  3220. void  PASCAL CreateParamQuery(QTSTRUCT *lpqt, FIELDINFO *rgFields,UWORD cTypes)
  3221. {    
  3222.     RETCODE    rc=SQL_SUCCESS;
  3223.     UWORD        i;
  3224.     LPTSTR    pch=NULL;
  3225.     TCHAR        szQuery[MAX_QUERY_SIZE];
  3226.     SDWORD    sdw = SQL_DATA_AT_EXEC;
  3227.     UWORD        w,
  3228.                 ind;
  3229.  
  3230.  
  3231.     wsprintf(szQuery,TEXT("select %s from %s where "), lpqt->szColNames,lpqt->szTableName);
  3232.  
  3233.  
  3234.     for(i = 0, w = 0,ind=0; i < cTypes; i++) 
  3235.         {
  3236.         pch = qtMakeData(ind, i,&rgFields[i], lpqt->szDataItem);
  3237.  
  3238.         if ((rgFields[i].fSearchable == SQL_SEARCHABLE ||
  3239.             rgFields[i].fSearchable == SQL_ALL_EXCEPT_LIKE) &&
  3240.             pch && *pch) 
  3241.         {
  3242.             w++;
  3243.  
  3244.             switch(rgFields[i].wSQLType)
  3245.             {
  3246.                 case SQL_REAL:
  3247.                 case SQL_FLOAT:
  3248.                 case SQL_DOUBLE:
  3249.                     wsprintf(&szQuery[lstrlen(szQuery)],TEXT("%s < ? + 1 and "),
  3250.                         rgFields[i].szFieldName);
  3251.                     break;
  3252.                 default:
  3253.                     wsprintf(&szQuery[lstrlen(szQuery)],TEXT("%s = ? and "),
  3254.                         rgFields[i].szFieldName);
  3255.             }
  3256.  
  3257.             if(!fBindParameter)
  3258.             {
  3259.                 rc = SQLSetParam(hstmt, w,
  3260.                     SQL_C_TCHAR, rgFields[i].wSQLType,
  3261.                     rgFields[i].precision, rgFields[i].scale,
  3262.                     (LPTSTR)(UDWORD)i, &sdw);
  3263.                 RETCHECK(SQL_SUCCESS, rc,szSQLSETPARAM);
  3264.             }
  3265.             else
  3266.             {
  3267.                 rc = SQLBindParameter(hstmt, w, SQL_PARAM_INPUT,
  3268.                     SQL_C_TCHAR, rgFields[i].wSQLType,
  3269.                     rgFields[i].precision, rgFields[i].scale,
  3270.                     (LPTSTR)((UDWORD)i+BIND_PARM_OFFSET), 0, &sdw);
  3271.                 RETCHECK(SQL_SUCCESS, rc,szSQLBINDPARAMETER);
  3272.             }
  3273.  
  3274.             ind++;
  3275.         }
  3276.     }
  3277.  
  3278.     if (_tcsstr(szQuery,TEXT("and")))
  3279.     {
  3280.         /* remove the final "and " */
  3281.         szQuery[lstrlen(szQuery) - 5] = TEXT('\0');
  3282.     }
  3283.  
  3284.     lstrcpy(lpqt->szParamQuery, szQuery);
  3285.  
  3286. }
  3287.  
  3288. //-----------------------------------------------------------------------
  3289. //      Function:               TestSearchedQuery
  3290. //-----------------------------------------------------------------------
  3291.  
  3292. void  PASCAL TestSearchedQuery(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,
  3293.     UWORD cTypes,DSTRUCT  *lpd,BOOL fBindParameter)
  3294. {
  3295.     RETCODE    rc=SQL_SUCCESS;
  3296.     UWORD        i;
  3297.     LPTSTR        pch=NULL;
  3298.     SDWORD    sdw;
  3299.     UWORD        w;
  3300.     UDWORD    udw;
  3301.     UWORD        ind;
  3302.  
  3303.  
  3304.     wsprintf(lpqt->sz, TEXT("select %s from %s where "), lpqt->szColNames,
  3305.         lpqt->szTableName);
  3306.  
  3307.     sdw = SQL_DATA_AT_EXEC;
  3308.  
  3309.     for(i = 0, w = 0,ind=0; i < cTypes; i++) 
  3310.         {
  3311.         pch = qtMakeData(ind, i,&rgFields[i], lpqt->szDataItem);
  3312.  
  3313.         if ((rgFields[i].fSearchable == SQL_SEARCHABLE ||
  3314.             rgFields[i].fSearchable == SQL_ALL_EXCEPT_LIKE) &&
  3315.             pch && *pch) {
  3316.             w++;
  3317.             switch(rgFields[i].wSQLType) {
  3318.                 case SQL_REAL:
  3319.                 case SQL_FLOAT:
  3320.                 case SQL_DOUBLE:
  3321.                     wsprintf(&lpqt->sz[lstrlen(lpqt->sz)], TEXT("%s < ? + 1 and "),
  3322.                         rgFields[i].szFieldName);
  3323.                     break;
  3324.                 default:
  3325.                     wsprintf(&lpqt->sz[lstrlen(lpqt->sz)], TEXT("%s = ? and "),
  3326.                     rgFields[i].szFieldName);
  3327.             }
  3328.  
  3329.             if(!fBindParameter){
  3330.                 rc = SQLSetParam(hstmt, w,
  3331.                     SQL_C_TCHAR, rgFields[i].wSQLType,
  3332.                     rgFields[i].precision, rgFields[i].scale,
  3333.                     (LPTSTR)(UDWORD)i, &sdw);
  3334.                 RETCHECK(SQL_SUCCESS, rc, szSQLSETPARAM);
  3335.                 }
  3336.             else{
  3337.                 rc = SQLBindParameter(hstmt, w, SQL_PARAM_INPUT,
  3338.                     SQL_C_TCHAR, rgFields[i].wSQLType,
  3339.                     rgFields[i].precision, rgFields[i].scale,
  3340.                     (LPTSTR)((UDWORD)i+BIND_PARM_OFFSET), 0, &sdw);
  3341.                 RETCHECK(SQL_SUCCESS, rc, szSQLBINDPARAMETER);
  3342.                 }
  3343.  
  3344.             ind++;
  3345.         }
  3346.     }
  3347.     /* remove the final "and " */
  3348.     lpqt->sz[lstrlen(lpqt->sz) - 5] = TEXT('\0');
  3349.     lstrcpy(lpqt->szParamQuery, lpqt->sz);
  3350.  
  3351.     rc = SQLPrepare(hstmt, lpqt->sz, SQL_NTS);
  3352.     RETCHECK(SQL_SUCCESS, rc, szSQLPREPARE);
  3353.  
  3354.     rc = SQLExecute(hstmt);
  3355.     RETCHECK(SQL_NEED_DATA, rc, szSQLEXECUTE);
  3356.  
  3357.     udw = cTypes;
  3358.  
  3359.     for(i = 0; ; i++) 
  3360.         {
  3361.         rc = SQLParamData(hstmt, (PTR *)&udw);
  3362.         if(rc != SQL_NEED_DATA)
  3363.             break;
  3364.  
  3365.         if(udw-BIND_PARM_OFFSET < cTypes)
  3366.             pch = qtMakeData(cTypes, i,&rgFields[udw-BIND_PARM_OFFSET], lpqt->szDataItem);
  3367.         else
  3368.             DISPLAYERROR(szSQLPARAMDATA, TEXT("invalid rgbValue"));
  3369.  
  3370.         if(*pch) 
  3371.             {
  3372.             udw = lstrlen(pch);
  3373.             rc = SQLPutData(hstmt, pch, (SDWORD)lstrlen(pch));
  3374.             RETCHECK(SQL_SUCCESS, rc, szSQLPUTDATA);
  3375.             } 
  3376.         else
  3377.             {
  3378.             rc = SQLPutData(hstmt, (LPTSTR)IGNORED, SQL_NULL_DATA);
  3379.             RETCHECK(SQL_SUCCESS, rc, szSQLPUTDATA);
  3380.             }
  3381.         }
  3382.  
  3383.     RETCHECK(SQL_SUCCESS, rc, szSQLPARAMDATA);
  3384.  
  3385.     for(i = 0;; i++) 
  3386.         {
  3387.         rc = SQLFetch(hstmt);
  3388.  
  3389.         if(rc != SQL_SUCCESS)
  3390.             break;
  3391.         }
  3392.  
  3393.     RETCHECK(SQL_NO_DATA_FOUND, rc, szSQLFETCH);
  3394.  
  3395.     /* should have gotten 1 row back */
  3396.  
  3397.     if(i != 1)
  3398.         DISPLAYERROR(TEXT("Param/PutData"), TEXT("incorrect number of rows returned"));
  3399.  
  3400.     FreeStmt(SQL_CLOSE);
  3401.  
  3402. } //TestSearchedQuery()
  3403.  
  3404.  
  3405.  
  3406. //-----------------------------------------------------------------------
  3407. //      Function:               TestLargeQuery
  3408. //-----------------------------------------------------------------------
  3409.  
  3410. void  PASCAL TestLargeQuery(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,
  3411.     UWORD cTypes,DSTRUCT  *lpd)
  3412. {
  3413.     RETCODE    rc=SQL_SUCCESS;
  3414.     UWORD        ind=0,
  3415.                 i;
  3416.     LPTSTR    pch=NULL;
  3417.     TCHAR        szQuery[2048];
  3418.  
  3419.  
  3420.     /* > 1K query */
  3421.     wsprintf(szQuery,TEXT("select %s from %s where "), lpqt->szColNames,
  3422.         lpqt->szTableName);
  3423.  
  3424.     for(i = 0; i < cTypes; i++) 
  3425.         {
  3426.         if (rgFields[i].fSearchable == SQL_SEARCHABLE ||
  3427.             rgFields[i].fSearchable == SQL_ALL_EXCEPT_LIKE)
  3428.             break;
  3429.         }
  3430.  
  3431.     pch = qtMakeData(cTypes, 1, &rgFields[i], lpqt->szDataItem);
  3432.     while(lstrlen(szQuery) < 1024L) 
  3433.         {
  3434.         int li=lstrlen(szQuery);
  3435.         switch(rgFields[i].wSQLType) 
  3436.             {
  3437.             case SQL_REAL:
  3438.             case SQL_FLOAT:
  3439.             case SQL_DOUBLE:
  3440.                 wsprintf(&szQuery[lstrlen(szQuery)],TEXT("%s < %s + 1 and "),
  3441.                     rgFields[i].szFieldName, pch);
  3442.                 break;
  3443.             default:
  3444.                 wsprintf(&szQuery[lstrlen(szQuery)],TEXT("%s = %s%s%s and "),
  3445.                 rgFields[i].szFieldName, rgFields[i].szPrefix, pch, rgFields[i].szSuffix);
  3446.                 break;
  3447.             }
  3448.         }
  3449.  
  3450.     /* remove the final "and " */
  3451.     szQuery[lstrlen(szQuery) - 5] = TEXT('\0');
  3452.                 
  3453.     rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
  3454.     RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  3455.  
  3456.     if (RC_SUCCESSFUL(rc))
  3457.         {
  3458.         for(i = 0;; i++) 
  3459.             {
  3460.             rc = SQLFetch(hstmt);
  3461.  
  3462.             if(rc != SQL_SUCCESS)
  3463.                 break;
  3464.             }
  3465.  
  3466.         RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH);
  3467.  
  3468.         /* should have gotten at least 1 row back */
  3469.  
  3470.         if(i < 1)
  3471.             DISPLAYERROR(TEXT("> 1K query"),TEXT("incorrect number of rows returned"));
  3472.  
  3473.         }
  3474.             
  3475.     /* SQLFreeStmt with SQL_CLOSE to re-use the hstmt */
  3476.  
  3477.     FreeStmt(SQL_CLOSE);
  3478.  
  3479. } //TestLargeQuery()
  3480.  
  3481.  
  3482.  
  3483. //-----------------------------------------------------------------------
  3484. //      Function:               TestSQLTables
  3485. //-----------------------------------------------------------------------
  3486.  
  3487. void  PASCAL TestSQLTables(QTSTRUCT  *lpqt)
  3488. {
  3489.     RETCODE    rc=SQL_SUCCESS;
  3490.     BOOL        fFoundTable=FALSE;    
  3491.     UWORD        i;
  3492.  
  3493.     /* this call may return many tables, as  */
  3494.     /* long as the one created earlier shows */
  3495.     /* up it will pass. */
  3496.         
  3497.     rc = SQLTables(hstmt, NULL, 0, NULL, 0,TEXT("q%"),SQL_NTS,TEXT("'TABLE'"), SQL_NTS); 
  3498.  
  3499.     RETCHECK(SQL_SUCCESS, rc,szSQLTABLES);
  3500.  
  3501.     for(i = 0;; i++) 
  3502.         {
  3503.         rc = SQLFetch(hstmt);
  3504.         if(rc != SQL_SUCCESS)
  3505.             break;
  3506.  
  3507.         /* column 3 is tablename */
  3508.         rc = SQLGetData(hstmt, 3, SQL_C_TCHAR, lpqt->sz, MAX_STRING_SIZE, NULL);
  3509.         RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA); /* should not overflow
  3510.             and return SQL_SUCCESS_WITH_INFO because the buffer is larger than the
  3511.             table name */
  3512.         fFoundTable += 0 == lstrcmpi(lpqt->sz, lpqt->szTableName);
  3513.         }
  3514.  
  3515.     RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH);
  3516.  
  3517.     if(1 != fFoundTable) {
  3518.         DISPLAYERROR(szSQLTABLES,TEXT("table not found"));
  3519.     }
  3520.  
  3521.     FreeStmt(SQL_CLOSE);
  3522.  
  3523. } //TestSQLTables()
  3524.  
  3525.  
  3526. //-----------------------------------------------------------------------
  3527. //      Function:               TestSQLSpecialCols
  3528. //-----------------------------------------------------------------------
  3529.  
  3530. void  PASCAL TestSQLSpecialCols(QTSTRUCT  *lpqt)
  3531. {
  3532.     RETCODE    rc=SQL_SUCCESS;
  3533.     UWORD        i;
  3534.  
  3535.     rc = SQLSpecialColumns(hstmt, SQL_BEST_ROWID, NULL, 0, NULL, 0,
  3536.         lpqt->szTableName, (SWORD)(lstrlen(lpqt->szTableName)), SQL_SCOPE_TRANSACTION,
  3537.         SQL_NULLABLE);
  3538.     RETCHECK(SQL_SUCCESS, rc,szSQLSPECIALCOLUMNS);
  3539.  
  3540.     for(i = 0;; i++)
  3541.         {
  3542.         rc = SQLFetch(hstmt);
  3543.         if(rc != SQL_SUCCESS)
  3544.             break;
  3545.         }
  3546.  
  3547.     RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH);
  3548.  
  3549.     FreeStmt(SQL_CLOSE);
  3550.  
  3551. } //TestSQLSpecialCols()
  3552.  
  3553.  
  3554.  
  3555.  
  3556. //-----------------------------------------------------------------------
  3557. //      Function:               VerifyIndex
  3558. //-----------------------------------------------------------------------
  3559.  
  3560. void  PASCAL VerifyIndex(QTSTRUCT  *lpqt,UWORD fIndex)
  3561. {
  3562.     RETCODE    rc=SQL_SUCCESS;
  3563.     BOOL        fFoundTable=FALSE;
  3564.     UWORD        i;
  3565.     SDWORD    sdw;
  3566.  
  3567.     rc = SQLStatistics(hstmt, NULL, 0, NULL, 0, lpqt->szTableName,
  3568.     SQL_NTS, SQL_INDEX_ALL, SQL_ENSURE);
  3569.     RETCHECK(SQL_SUCCESS, rc,TEXT("SQLStatistics"));
  3570.  
  3571.     fFoundTable = 0;
  3572.     for(i = 0;; i++) 
  3573.         {
  3574.         rc = SQLFetch(hstmt);
  3575.         if(rc != SQL_SUCCESS)
  3576.             break;
  3577.  
  3578.         rc = SQLGetData(hstmt, 3, SQL_C_TCHAR, lpqt->sz, MAX_STRING_SIZE,
  3579.             &sdw);
  3580.         RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA);
  3581.         if (lstrcmpi(lpqt->sz, lpqt->szTableName) == 0)
  3582.             {
  3583.             rc = SQLGetData(hstmt, 6, SQL_C_TCHAR, lpqt->sz, MAX_STRING_SIZE,
  3584.                 &sdw);
  3585.             RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA);
  3586.             fFoundTable += 0 == lstrcmpi(lpqt->sz, lpqt->szDataItem);
  3587.             }
  3588.         }
  3589.  
  3590.     RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH);
  3591.  
  3592.     if(1 != fFoundTable && fIndex)
  3593.         DISPLAYERROR(TEXT("SQLStatistics"),TEXT("index not returned"));
  3594.  
  3595.     /* one row represents original table, the */
  3596.     /* other represents the index                 */
  3597.     if(i > 2 || i < 1) 
  3598.         DISPLAYERROR(TEXT("SQLStatistics"),TEXT("too many rows"));
  3599.  
  3600.     FreeStmt(SQL_CLOSE);
  3601.  
  3602. } //VerifyIndex()
  3603.  
  3604. //-----------------------------------------------------------------------
  3605. //      Function:               TestSQLStatistics
  3606. //-----------------------------------------------------------------------
  3607.  
  3608. BOOL  PASCAL TestSQLStatistics(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,
  3609.     UWORD cTypes,DSTRUCT  *lpd,UWORD fIndex)
  3610. {
  3611.     RETCODE    rc=SQL_SUCCESS;
  3612.     UWORD        i;
  3613.  
  3614.     lstrcpy(lpqt->szDataItem, lpqt->szTableName);
  3615.     lpqt->szDataItem[0] = TEXT('i');
  3616.     for(i = 1; i < cTypes; i++)
  3617.         if(rgFields[i].wSQLType == SQL_INTEGER ||
  3618.             rgFields[i].wSQLType == SQL_SMALLINT)
  3619.             break;
  3620.     if(i == cTypes)
  3621.         i = 0;
  3622.  
  3623.     lstrcpy(lpqt->buf, rgFields[i].szFieldName);
  3624.     wsprintf(lpqt->sz,TEXT("create unique index %s on %s (%s)"),
  3625.         lpqt->szDataItem, lpqt->szTableName, lpqt->buf);
  3626.  
  3627.     rc = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  3628.     if(fIndex < 1)
  3629.         /* if this is minimal grammar, don't count on indexes being available */
  3630.         fIndex = rc == SQL_SUCCESS;
  3631.     else
  3632.         RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  3633.  
  3634.     VerifyIndex(lpqt,fIndex);
  3635.  
  3636.     return(fIndex);
  3637.  
  3638. } //TestSQLStatistics()
  3639.  
  3640.  
  3641. //-----------------------------------------------------------------------
  3642. //      Function:               TestLikeQuery
  3643. //-----------------------------------------------------------------------
  3644.  
  3645. void  PASCAL TestLikeQuery(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,
  3646.     UWORD cTypes,DSTRUCT  *lpd)
  3647. {
  3648.     RETCODE    rc=SQL_SUCCESS;
  3649.     UWORD    i;
  3650.     SDWORD    cbValue=0;
  3651.  
  3652.     for(i = 0; i < cTypes; i++) 
  3653.         {
  3654.         if(rgFields[i].fSearchable == SQL_LIKE_ONLY ||
  3655.             rgFields[i].fSearchable == SQL_SEARCHABLE) 
  3656.             {
  3657.             lstrcpy(lpqt->buf, rgFields[i].szFieldName);
  3658.             break;
  3659.             }
  3660.     }
  3661.  
  3662.     if(i < cTypes) 
  3663.         {
  3664.  
  3665.         /* execute a query using like.  This query should return all records */
  3666.         /* this query should return all rows in the table                             */
  3667.  
  3668.         wsprintf(lpqt->sz,TEXT("select * from %s where %s not like 'a'"), lpqt->szTableName,
  3669.             lpqt->buf, lpqt->buf);
  3670.         rc = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  3671.         RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  3672.  
  3673.         for(i = 0;; i++) 
  3674.             {
  3675.             rc = SQLFetch(hstmt);
  3676.             if(rc != SQL_SUCCESS)
  3677.                 break;
  3678.  
  3679.             rc = SQLGetData(hstmt, 1, SQL_C_TCHAR, lpqt->sz, MAX_STRING_SIZE,
  3680.                 &cbValue);
  3681.             if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
  3682.                 RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA);
  3683.             }
  3684.  
  3685.         RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH);
  3686.  
  3687.         if(i != cTypes)
  3688.             DISPLAYERROR(TEXT("'LIKE' query"),TEXT("incorrect number of result rows"));
  3689.  
  3690.         }
  3691.  
  3692.     FreeStmt(SQL_CLOSE);
  3693.  
  3694. } //TestLikeQuery()
  3695.  
  3696.  
  3697. //-----------------------------------------------------------------------
  3698. //      Function:               TestLikeQuery
  3699. //-----------------------------------------------------------------------
  3700.  
  3701. void  PASCAL TestOJCap(QTSTRUCT  *lpqt)
  3702. {
  3703.     RETCODE    rc=SQL_SUCCESS;
  3704.     UDWORD    udw;
  3705.  
  3706.     rc = SQLGetInfo(hdbc, (UWORD)SQL_OJ_CAPABILITIES, &udw, (SWORD)(sizeof(udw)), NULL);
  3707.     if(RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO))
  3708.     {
  3709.         udw &= ~(SQL_OJ_LEFT | SQL_OJ_RIGHT | SQL_OJ_FULL | SQL_OJ_NESTED    |
  3710.                     SQL_OJ_NOT_ORDERED | SQL_OJ_INNER | SQL_OJ_ALL_COMPARISON_OPS);
  3711.         if(udw)
  3712.         {
  3713.             wsprintf(lpqt->buf,TEXT("Undefined flags return from SQLGetInfo(...SQL_OJ_CAPABILITIES...) = %lX"), udw);
  3714.             DISPLAYERROR(szSQLGETINFO, lpqt->buf);
  3715.         }
  3716.     }
  3717.  
  3718.     rc = SQLGetInfo(hdbc, SQL_OUTER_JOINS, lpqt->buf, MAX_STRING_SIZE, NULL);
  3719.     if(RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO)){
  3720.         *lpqt->buf = toupper(*lpqt->buf);
  3721.         if((!_tcsnccmp(lpqt->buf,TEXT("Y"), 1)) && (!_tcsnccmp(lpqt->buf,TEXT("N"), 1)))
  3722.             DISPLAYERROR(szSQLGETINFO,TEXT("Driver returned an invalid value for SQLGetInfo(...SQL_OUTER_JOINS...).  The only valid values are \"Y\" and \"N\"."));
  3723.         }
  3724.  
  3725. } //TestOJCap()
  3726.  
  3727.  
  3728. /*-----------------------------------------------------------------------
  3729.  *      Function:               TestExtendedFetch
  3730.  *-----------------------------------------------------------------------*/
  3731.  
  3732. void  PASCAL TestExtendedFetch(QTSTRUCT  *lpqt, FIELDINFO  *rgFields, UWORD cTypes)
  3733. {
  3734.     RETCODE    rc=SQL_SUCCESS;
  3735.     WORD        fLevel2 = FALSE;
  3736.     DWORD        dwLen=0;
  3737.     SWORD        fSqlType;
  3738.     SDWORD    cbValue=0;
  3739.     UWORD        iTableCol,row,iCol,uwRowSetSize;
  3740.     TCHAR        szQuery[MAX_STRING_SIZE], szColName[SMALLBUFF];
  3741.     TCHAR*    rgbValue;
  3742.     DSTRUCT*    rgData;
  3743.     DSTRUCT*    pDataBuf;
  3744.     BOOL        fCol0Bound=TRUE;
  3745.  
  3746.     uwRowSetSize=5; /* Cinco seems like a good rowset size */
  3747.  
  3748.     /* Only col which might not be bound but might not be AutoUpdateable is col 0 */
  3749.     if(!qtMakeData(0, 0, &rgFields[0], szQuery))
  3750.         fCol0Bound = FALSE;
  3751.  
  3752.     SelectFromTable(lpqt);
  3753.  
  3754.     rc = SQLBindCol(hstmt, 1, SQL_C_BINARY, lpqt->sz, MAX_BIND_ARRAY_ELEMENT,
  3755.         &cbValue);
  3756.     RETCHECK(SQL_SUCCESS, rc,szSQLBINDCOL);
  3757.  
  3758.     if (!Supported(SQL_API_SQLEXTENDEDFETCH)) 
  3759.     {
  3760.         rc = SQLExtendedFetch(hstmt, SQL_FETCH_FIRST, IGNORED, NULL, NULL);
  3761.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  3762.             DISPLAYERROR(szSQLEXTENDEDFETCH, szNotSupported);
  3763.         RETCHECK(SQL_ERROR, rc,szSQLEXTENDEDFETCH);
  3764.  
  3765.         FreeStmt(SQL_CLOSE);
  3766.         return;
  3767.     } 
  3768.  
  3769.     rc = SQLGetStmtOption(hstmt,SQL_CURSOR_TYPE,&dwLen);
  3770.     RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTOPTION);
  3771.  
  3772.     if(dwLen != SQL_CURSOR_FORWARD_ONLY)
  3773.         {
  3774.         rc = SQLExtendedFetch(hstmt, SQL_FETCH_FIRST, IGNORED, NULL, NULL);
  3775.         RETCHECK(SQL_SUCCESS, rc,szSQLEXTENDEDFETCH);
  3776.         }
  3777.     else
  3778.         {
  3779.         rc = SQLExtendedFetch(hstmt, SQL_FETCH_FIRST, IGNORED, NULL, NULL);
  3780.         RETCHECK(SQL_ERROR, rc,szSQLEXTENDEDFETCH);
  3781.         }
  3782.  
  3783.     rc = SQLFreeStmt(hstmt, SQL_CLOSE);
  3784.     RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT);
  3785.  
  3786.     rc = SQLFreeStmt(hstmt, SQL_UNBIND);
  3787.     RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT);
  3788.  
  3789.     rc = SQLFreeStmt(hstmt, SQL_RESET_PARAMS);
  3790.     RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT);
  3791.  
  3792.     /* Allocate an area for ExtendedFetch to take place */
  3793.     if (!(rgData = AllocateMemory(sizeof(DSTRUCT)*cTypes*uwRowSetSize))){
  3794.         DISPLAYERROR(szSQLEXTENDEDFETCH,TEXT("Insufficient Memory Available"));
  3795.         return;    
  3796.     }
  3797.  
  3798.     /* Allocate an area for test data */
  3799.     if (!(rgbValue = AllocateMemory(MAX_STRING_SIZE))){
  3800.         DISPLAYERROR(szSQLEXTENDEDFETCH,TEXT("Insufficient Memory Available"));
  3801.         ReleaseMemory(rgData);
  3802.         return;
  3803.     }
  3804.  
  3805.     /* Get column for "order by" clause: */
  3806.     wsprintf(szQuery,TEXT("select %s from %s"),lpqt->szColNames, lpqt->szTableName);
  3807.     rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
  3808.     if((SQL_SUCCESS!=rc) && (SQL_SUCCESS_WITH_INFO!=rc)){
  3809.         RETCHECK(SQL_SUCCESS_WITH_INFO, rc, szSQLEXECDIRECT);
  3810.         goto abortxfetch;
  3811.     }
  3812.     iCol=0;
  3813.     do    {
  3814.         iCol++;
  3815.         rc=SQLDescribeCol(hstmt, iCol, szColName, (SMALLBUFF*sizeof(TCHAR)), 
  3816.             NULL, &fSqlType, NULL, NULL, NULL);
  3817.         RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBECOL);
  3818.     } while(fSqlType!=SQL_CHAR && iCol<=cTypes);
  3819.  
  3820.     FreeStmt(SQL_CLOSE);
  3821.     if(iCol>cTypes){
  3822.         DISPLAYERROR(szSQLEXTENDEDFETCH, TEXT("\t\t\tSelect-order by  Failed"));
  3823.         goto abortxfetch;
  3824.     }
  3825.  
  3826.     /* Set rowset size and set to row-wise binding:  */
  3827.     rc = SQLSetStmtOption(hstmt, SQL_ROWSET_SIZE, (UDWORD)uwRowSetSize);
  3828.     if (SQL_SUCCESS != rc){
  3829.         DISPLAYERROR(TEXT("ExtendedFetch...SQLSetStmtOption(Rowset_Size)"),
  3830.             TEXT("SQLSetStmtOption Failed"));
  3831.         GetErrors(henv, hdbc,hstmt);
  3832.     }    
  3833.     rc = SQLSetStmtOption(hstmt, SQL_BIND_TYPE, (sizeof(DSTRUCT)*cTypes));
  3834.     if (SQL_SUCCESS != rc){
  3835.         DISPLAYERROR(TEXT("ExtendedFetch...SQLSetStmtOption(Bind_Type)"),
  3836.             TEXT("SQLSetStmtOption Failed"));
  3837.         GetErrors(henv, hdbc,hstmt);
  3838.     }
  3839.  
  3840.     if(SQL_SUCCESS != SelectFromTableFetch(lpqt, szColName)){
  3841.         DISPLAYERROR(szSQLEXTENDEDFETCH, TEXT("\t\t\tSelect-order by  Failed"));
  3842.         goto abortxfetch;
  3843.     }
  3844.     if (!BindFetchColumns(lpqt, rgFields, cTypes, rgData)){
  3845.         DISPLAYERROR(szSQLEXTENDEDFETCH, szSQLBINDCOL);
  3846.         goto abortxfetch;
  3847.     }
  3848.     /* Fetch into allocated area rowset to be tested */
  3849.     rc = SQLExtendedFetch(hstmt, SQL_FETCH_NEXT, 1, NULL, NULL);
  3850.     if (SQL_SUCCESS != rc){
  3851.         RETCHECK(SQL_SUCCESS, rc,szSQLEXTENDEDFETCH);
  3852.         DISPLAYERROR(szSQLEXTENDEDFETCH, TEXT("Fetch Failed"));
  3853.         goto abortxfetch;
  3854.     }
  3855.  
  3856.     rc = SQLFreeStmt(hstmt, SQL_CLOSE);
  3857.     RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT);
  3858.  
  3859.     rc = SQLFreeStmt(hstmt, SQL_UNBIND);
  3860.     RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT);
  3861.     
  3862.     /* Set rowset size to "1" to test each row of rowset independently:  */
  3863.     rc = SQLSetStmtOption(hstmt, SQL_ROWSET_SIZE, (UDWORD)(1));
  3864.     if (SQL_SUCCESS != rc){
  3865.         DISPLAYERROR(TEXT("ExtendedFetch...SQLSetStmtOption(Rowset_Size)"),
  3866.             TEXT("SQLSetStmtOption Failed"));
  3867.         GetErrors(henv, hdbc,hstmt);
  3868.     }    
  3869.  
  3870.      /* Check data in all rows of rowset */ 
  3871.     if(SQL_SUCCESS != SelectFromTableFetch(lpqt, szColName)){
  3872.         DISPLAYERROR(szSQLEXTENDEDFETCH, TEXT("\t\t\tSelect-order by  Failed"));
  3873.         goto abortxfetch;
  3874.     }
  3875.  
  3876.     // Need to change this loop if number of rows in table < uwRowSetSize
  3877.     for (row=0; row<uwRowSetSize; row++)
  3878.     {
  3879.         SWORD iResultSetCol=0;
  3880.         if (SQL_SUCCESS != (rc = SQLFetch(hstmt))){
  3881.             RETCHECK(SQL_SUCCESS, rc, szSQLFETCH);
  3882.             DISPLAYERROR(szSQLEXTENDEDFETCH, TEXT("Fetch Failed"));
  3883.             goto abortxfetch;
  3884.         }
  3885.             
  3886.         pDataBuf=rgData+row*cTypes;
  3887.         for (iTableCol=0; iTableCol<cTypes; iTableCol++)
  3888.         {
  3889.             /* Ignore columns which aren't bound as they aren't in the result set */
  3890.             if((!iTableCol && !fCol0Bound) || rgFields[iTableCol].fAutoUpdate)
  3891.                 continue;    
  3892.  
  3893.             iResultSetCol++;
  3894.             rc = SQLGetData(hstmt, iResultSetCol, SQL_C_TCHAR, rgbValue, MAX_STRING_SIZE,
  3895.                  &cbValue);
  3896.             if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
  3897.                 RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA);
  3898.  
  3899.             if(!CheckDataResults(row, iTableCol, &rgFields[iTableCol], pDataBuf,cbValue,rgbValue))
  3900.             {
  3901.                 wsprintf(lpqt->buf, TEXT("Data Check Failed, Row %d, Table Col %d, DataType %d (%s)"),
  3902.                     row, iTableCol, rgFields[iTableCol].wSQLType, rgFields[iTableCol].szFieldName) ;
  3903.                 szWrite(lpqt->buf,FALSE);
  3904.                 rgbValue[MAX_STRING_SIZE-1]=TEXT('\0');
  3905.                 wsprintf(lpqt->buf, TEXT("Returned Data: (%s)"), rgbValue);
  3906.                 DISPLAYERROR(TEXT("ExtendedFetch"),lpqt->buf);
  3907.                 // goto abortxfetch;
  3908.             }
  3909.         }
  3910.     }
  3911.  
  3912. abortxfetch:
  3913.     FreeStmt(SQL_CLOSE);
  3914.     FreeStmt(SQL_UNBIND);
  3915.     ReleaseMemory(rgData);
  3916.     ReleaseMemory(rgbValue);
  3917. } /* TestExtendedFetch() */
  3918.  
  3919.  
  3920.  
  3921.  
  3922. /*------------------------------------------------------------------------------
  3923.  *      Function:       TestQuickRebind Feature 
  3924.  *      Purpose:        To test this specific feature, not the function(s) using it.
  3925.  *      Synopsis:
  3926.  *      An area large enough for 12 rows of QRDSTRUCTs will be created. There will 
  3927.  * be two rows of the result set per Rowset. Rowset 1 should be duplicated
  3928.  * in rows 0,1 and 3,4, while Rowset 2 should be duplicated in rows 6,7 and 9,10. 
  3929.  * Thus, rows 0 and 3 will contain the first row of the result set, rows 1 and 
  3930.  * 4 will contain the second row of the result set, etc.  Rows 2, 5, 8, and
  3931.  * 11 should have their preset condition of all zeroes remain unchanged.
  3932.  * ----------------------------------------------------------------------------*/
  3933.  
  3934. void  PASCAL TestQuickRebind(QTSTRUCT * lpqt, FIELDINFO  *rgFields, UWORD cTypes,
  3935.                                       DSTRUCT  *lpd)
  3936. {
  3937.     RETCODE    rc;
  3938.     UWORD        row,iCol,iRowset,uwRowsetSize,iRowsetRow,iTableCol;
  3939.     UDWORD    udwRowSize;
  3940.     SWORD        fSqlType;
  3941.     SDWORD    sdwOffset;
  3942.     DSTRUCT    *rgData, *pZeroRow;
  3943.     DSTRUCT    *pCurrentRowData;
  3944.     TCHAR        szQuery[MAX_STRING_SIZE], szColName[SMALLBUFF];
  3945.     SDWORD    cbValue;
  3946.     TCHAR*    rgbValue=NULL;
  3947.     BOOL        fCol0Bound=TRUE;
  3948.                                                                         
  3949.     udwRowSize = sizeof(DSTRUCT)*cTypes;
  3950.                         /* cNumResSetCols is set in BuildInsertStmt() */
  3951.     uwRowsetSize = 5;/* uwRowsetSize rows per Rowset */
  3952.  
  3953.     /* Only col which might not be bound but might not be AutoUpdateable is col 0 */
  3954.     if(!qtMakeData(0, 0, &rgFields[0], szQuery))
  3955.         fCol0Bound = FALSE;
  3956.  
  3957.     /* Allocate an area for QuickRebind to take place */
  3958.     if (!(rgData = AllocateMemory(NUM_QUIKREBIND_ROWSETS*(uwRowsetSize+1)*udwRowSize) )){
  3959.         DISPLAYERROR(szQUICKREBIND,TEXT("\t\t\tInsufficient Memory Available"));
  3960.         return;
  3961.     }
  3962.  
  3963.     /* Allocate an area for a row of zeroes to place between each Rowset. */
  3964.     if (!(pZeroRow = AllocateMemory(udwRowSize) )){
  3965.         DISPLAYERROR(szQUICKREBIND,TEXT("\t\t\tInsufficient Memory Available"));
  3966.         goto abortQuikRebind;
  3967.     }
  3968.  
  3969.     /* Allocate an area for test data */
  3970.     if (!(rgbValue = AllocateMemory(MAX_STRING_SIZE))){
  3971.         DISPLAYERROR(szSQLEXTENDEDFETCH,TEXT("Insufficient Memory Available"));
  3972.         goto abortQuikRebind;
  3973.     }
  3974.  
  3975.     ResetHstmt(&hstmt);
  3976.  
  3977.     /* Get column for "order by" clause: */
  3978.     wsprintf(szQuery,TEXT("select %s from %s"),lpqt->szColNames, lpqt->szTableName);
  3979.     rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
  3980.     if((SQL_SUCCESS!=rc) && (SQL_SUCCESS_WITH_INFO!=rc)){
  3981.         RETCHECK(SQL_SUCCESS_WITH_INFO, rc, szSQLEXECDIRECT);
  3982.         goto abortQuikRebind;
  3983.     }
  3984.     iCol=0;
  3985.     do    {
  3986.         iCol++;
  3987.         rc=SQLDescribeCol(hstmt, iCol, szColName, (SMALLBUFF*sizeof(TCHAR)), 
  3988.             NULL, &fSqlType, NULL, NULL, NULL);
  3989.         RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBECOL);
  3990.     } while(fSqlType!=SQL_CHAR && iCol<=cTypes);
  3991.  
  3992.     FreeStmt(SQL_CLOSE);
  3993.     if(iCol>=cTypes){
  3994.         DISPLAYERROR(szQUICKREBIND, TEXT("\t\t\tSelect-order by  Failed"));
  3995.         goto abortQuikRebind;
  3996.     }
  3997.  
  3998.     /* Set to row-wise binding and set Rowset size to uwRowsetSize:  */
  3999.     rc = SQLSetStmtAttr(hstmt,SQL_ATTR_ROW_BIND_TYPE,(PTR)udwRowSize,SQL_IS_INTEGER);
  4000.     if (SQL_SUCCESS != rc){
  4001.         _tcscpy(lpqt->buf,TEXT("\t\t\tQuick Rebind FAILED...SQLSetDescField(Bind_Type)"));
  4002.         szWrite(lpqt->buf, TRUE);
  4003.         goto abortQuikRebind;
  4004.     }
  4005.     rc = SQLSetStmtAttr(hstmt,SQL_ATTR_ROW_ARRAY_SIZE,(PTR)uwRowsetSize,SQL_IS_INTEGER);
  4006.     if (SQL_SUCCESS != rc){
  4007.             DISPLAYERROR(szQUICKREBIND,TEXT("\t\t\tSetStmtAttr(Rowset Size)"));
  4008.         goto abortQuikRebind;
  4009.     }        
  4010.  
  4011.     /* Define area storing Quikrebind offset value: */
  4012.     rc = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, &sdwOffset, SQL_IS_POINTER);
  4013.     if (SQL_SUCCESS != rc){
  4014.         if(FindError(SQL_HANDLE_STMT,szHYC00)){
  4015.             _tcscpy(lpqt->buf,TEXT("\t\t\tQuickRebind Not Supported"));
  4016.             szWrite(lpqt->buf, TRUE);
  4017.             goto abortQuikRebind;
  4018.         }
  4019.         _tcscpy(lpqt->buf,TEXT("\t\t\tQuick Rebind FAILED...QuickRebind Not Functional"));
  4020.         szWrite(lpqt->buf, TRUE);
  4021.         goto abortQuikRebind;
  4022.     }
  4023.  
  4024.     if(SQL_SUCCESS != SelectFromTableFetch(lpqt, szColName)){
  4025.         DISPLAYERROR(szQUICKREBIND, TEXT("\t\t\tSelect-order by  Failed"));
  4026.         goto abortQuikRebind;
  4027.     }
  4028.  
  4029.     if (!BindFetchColumns(lpqt, rgFields, cTypes, rgData)){
  4030.         DISPLAYERROR(szQUICKREBIND,szSQLBINDCOL);
  4031.         goto abortQuikRebind;
  4032.     }
  4033.  
  4034.     /* Test quick rebind feature with two pairs of Rowsets, all *
  4035.      * rowsets separated by a row of zeroes:                    */
  4036.     for (iRowset=0; iRowset<=1; iRowset++)
  4037.     {
  4038.         if(iRowset)
  4039.             if(SQL_SUCCESS != SelectFromTableFetch(lpqt, szColName)){
  4040.                 DISPLAYERROR(szQUICKREBIND, TEXT("\t\t\tSelect-order by  Failed"));
  4041.                 goto abortQuikRebind;
  4042.             }
  4043.  
  4044.         /* Set offset value (to 0 or 1  * uwRowsetSize * udwRowSize) for 1st rowset */
  4045.         sdwOffset = iRowset*((1+uwRowsetSize)*udwRowSize);
  4046.  
  4047.         /* Fetch rowset into desired area */
  4048.         rc = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 1);
  4049.         if (SQL_SUCCESS != rc){
  4050.             ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_SUCCESS, rc, szSQLFETCHSCROLL);
  4051.             DISPLAYERROR(szQUICKREBIND,TEXT("Fetch Failed"));
  4052.             goto abortQuikRebind;
  4053.         }                                                                                                                                                                
  4054.                                                                 
  4055.         /* Set offset value (to 2 or 3 * uwRowsetSize * udwRowSize) for 2nd rowset */
  4056.         sdwOffset = (iRowset+2)*(1+uwRowsetSize)*udwRowSize;
  4057.  
  4058.         rc = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 1);
  4059.         if (SQL_SUCCESS != rc){
  4060.             ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_SUCCESS, rc, szSQLFETCHSCROLL);
  4061.             DISPLAYERROR(szQUICKREBIND,TEXT("Fetch Failed"));
  4062.             goto abortQuikRebind;
  4063.         }
  4064.         FreeStmt(SQL_CLOSE);
  4065.     }
  4066.     
  4067.     rc = SQLFreeStmt(hstmt, SQL_UNBIND);
  4068.     RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT);
  4069.  
  4070.     rc = SQLSetStmtAttr(hstmt,SQL_ATTR_ROW_ARRAY_SIZE,(PTR)1,SQL_IS_INTEGER);
  4071.     if (SQL_SUCCESS != rc){
  4072.             DISPLAYERROR(szQUICKREBIND,TEXT("\t\t\tSetStmtAttr(Rowset Size)"));
  4073.         goto abortQuikRebind;
  4074.     }
  4075.  
  4076.     /* Check stored values: */
  4077.     for (iRowset=0; iRowset<=1; iRowset++)
  4078.     {
  4079.         if(SQL_SUCCESS != SelectFromTableFetch(lpqt, szColName)){
  4080.             DISPLAYERROR(szQUICKREBIND, TEXT("\t\t\tSelect-order by  Failed"));
  4081.             goto abortQuikRebind;
  4082.         }
  4083.  
  4084.         /* First Rowset starts either in Allocated Row 0 or 3 */
  4085.         iRowsetRow= iRowset*(1+uwRowsetSize);  
  4086.         //for (row=0; row<NUM_QUIKREBIND_ROWSETS  ;row++,iRowsetRow++)
  4087.         for (row=0; row<(uwRowsetSize*2)  ;row++,iRowsetRow++)
  4088.         {
  4089.             UWORD iResultSetCol=0;
  4090.             if(row==uwRowsetSize)     
  4091.                 iRowsetRow+= 2+uwRowsetSize; /* Jump to 2nd Rowset */
  4092.  
  4093.             /* Don't check data in "zero" row,     *
  4094.              * the spacer row between rowsets:    */
  4095.             if(iRowsetRow%(1+uwRowsetSize) == uwRowsetSize)
  4096.                 continue;
  4097.  
  4098.             /* Fetch next rowset */
  4099.             rc = SQLFetch(hstmt);
  4100.             if (SQL_SUCCESS != rc){
  4101.                 ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_SUCCESS, rc, szSQLFETCH);
  4102.                 DISPLAYERROR(szQUICKREBIND,TEXT("Fetch Failed"));
  4103.                 goto abortQuikRebind;
  4104.             }                      
  4105.         
  4106.             pCurrentRowData = rgData+iRowsetRow*cTypes;
  4107.             for(iTableCol=0; iTableCol<cTypes; iTableCol++)
  4108.             {
  4109.                 /* Ignore columns which aren't bound as they aren't in the result set */
  4110.                 if((!iTableCol && !fCol0Bound) || rgFields[iTableCol].fAutoUpdate)
  4111.                     continue;    
  4112.  
  4113.                 iResultSetCol++;
  4114.                 rc = SQLGetData(hstmt, iResultSetCol, SQL_C_TCHAR, rgbValue, MAX_STRING_SIZE,
  4115.                     &cbValue);
  4116.                 if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
  4117.                     RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA);
  4118.  
  4119.                 if(!CheckDataResults(row, iTableCol, &rgFields[iTableCol], pCurrentRowData,cbValue,rgbValue))
  4120.                 {
  4121.                     wsprintf(lpqt->buf, TEXT("Data Check Failed, Row %d, Table Col %d, DataType %d (%s)"),
  4122.                         row, iTableCol, rgFields[iTableCol].wSQLType, rgFields[iTableCol].szFieldName) ;
  4123.                     szWrite(lpqt->buf,FALSE);
  4124.                     rgbValue[MAX_STRING_SIZE-1]=TEXT('\0');
  4125.                     wsprintf(lpqt->buf, TEXT("Returned Data: (%s)"), rgbValue);
  4126.                     DISPLAYERROR(szQUICKREBIND,lpqt->buf);
  4127.                     goto abortQuikRebind; 
  4128.                 }
  4129.             }/* end for(iTableCol) */
  4130.         } /* end for(row)              */
  4131.         FreeStmt(SQL_CLOSE);
  4132.     } /* end for (iRowset)  */
  4133.  
  4134.     /* Check Unused memory areas:    */
  4135.     for (iRowsetRow=uwRowsetSize; iRowsetRow<NUM_QUIKREBIND_ROWSETS*(uwRowsetSize+1);  )
  4136.     {
  4137.         pCurrentRowData = rgData+iRowsetRow*cTypes;
  4138.         if(memcmp(pCurrentRowData, pZeroRow, udwRowSize))
  4139.             DISPLAYERROR(szQUICKREBIND,
  4140.                     TEXT("Unused memory areas altered after Quick Rebind."));
  4141.         iRowsetRow+=(uwRowsetSize+1);
  4142.     }                                                        
  4143.                               
  4144.  
  4145. abortQuikRebind:
  4146.     ResetHstmt(&hstmt);
  4147.     if (rgbValue)                             
  4148.         ReleaseMemory(rgbValue);
  4149.     if (pZeroRow)                             
  4150.         ReleaseMemory(pZeroRow);
  4151.     ReleaseMemory(rgData);
  4152.  
  4153. } /* TestQuickRebind() */
  4154.  
  4155. //-----------------------------------------------------------------------
  4156. //      Function:               TestSQLForeignKeys
  4157. //-----------------------------------------------------------------------
  4158.  
  4159. void  PASCAL TestSQLForeignKeys(QTSTRUCT  *lpqt)
  4160. {
  4161.     RETCODE rc=SQL_SUCCESS;
  4162.  
  4163.     if (!Supported(SQL_API_SQLFOREIGNKEYS))
  4164.         {
  4165.         rc = SQLForeignKeys(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, 
  4166.             SQL_NTS, NULL, 0, NULL, 0, NULL, 0);
  4167.  
  4168.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4169.             DISPLAYERROR(szSQLFOREIGNKEYS, szNotSupported);
  4170.         RETCHECK(SQL_ERROR, rc,szSQLFOREIGNKEYS);
  4171.         }
  4172.     else
  4173.         {
  4174.         rc = SQLForeignKeys(hstmt, NULL, 0, NULL, 0, lpqt->szTableName,
  4175.             SQL_NTS, NULL, 0, NULL, 0, NULL, 0);
  4176.  
  4177.         RETCHECK(SQL_SUCCESS, rc,szSQLFOREIGNKEYS);
  4178.  
  4179.         while(rc == SQL_SUCCESS) 
  4180.             rc = SQLFetch(hstmt);
  4181.  
  4182.         RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH);
  4183.  
  4184.         FreeStmt(SQL_CLOSE);
  4185.  
  4186.         }
  4187.  
  4188. } //TestSQLForeignKeys()
  4189.  
  4190.  
  4191. //-----------------------------------------------------------------------
  4192. //      Function:               TestSQLBrowseConnect
  4193. //-----------------------------------------------------------------------
  4194.  
  4195. void  PASCAL TestSQLBrowseConnect(lpSERVERINFO lpSI)
  4196. {
  4197.     RETCODE    rc=SQL_SUCCESS;
  4198.     UWORD        cMaxConnections=0;
  4199.     TCHAR        szBCString[40];
  4200.     TCHAR        szDSN[40];
  4201.     HDBC        hdbcb=NULL;
  4202.  
  4203.     AllocHdbc(&hdbcb);
  4204.  
  4205.     rc = SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, &cMaxConnections, sizeof(int), NULL);
  4206.     RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO);
  4207.  
  4208.     if(cMaxConnections != 1) 
  4209.         {
  4210.         lstrcpy(szBCString,TEXT("DSN="));
  4211.         lstrcat(szBCString, lpSI->szValidServer0);
  4212.         
  4213.         if(lpSI->szValidServer0[0] == 0)
  4214.             {
  4215.             rc = SQLGetInfo(hdbc, SQL_DATA_SOURCE_NAME, &szDSN, 40, NULL);
  4216.             lstrcat(szBCString, szDSN);
  4217.             }
  4218.  
  4219.         if(!Supported(SQL_API_SQLBROWSECONNECT))
  4220.             {
  4221.             HDBC thdbc=NULL;
  4222.  
  4223.             rc = SQLBrowseConnect(hdbcb, szBCString, SQL_NTS, NULL, 0, NULL);
  4224.             thdbc = hdbc;
  4225.             hdbc = hdbcb;
  4226.             if(!FindError(SQL_HANDLE_DBC,szIM001))
  4227.                 DISPLAYERROR(szSQLBROWSECONNECT, szNotSupported);
  4228.             RETCHECK(SQL_ERROR, rc,szSQLBROWSECONNECT);
  4229.             hdbc = thdbc;
  4230.  
  4231.             rc = SQLFreeConnect(hdbcb);
  4232.             RETCHECK(SQL_SUCCESS, rc,szSQLFREECONNECT);
  4233.         
  4234.             }
  4235.         else
  4236.             {
  4237.             rc = SQLBrowseConnect(hdbcb, szBCString, SQL_NTS, NULL, 0, NULL);
  4238.             RETCHECK(SQL_NEED_DATA, rc,szSQLBROWSECONNECT);
  4239.  
  4240.             rc = SQLDisconnect(hdbcb);
  4241.             RETCHECK(SQL_SUCCESS, rc,szSQLDISCONNECT);
  4242.             rc = SQLFreeConnect(hdbcb);
  4243.             RETCHECK(SQL_SUCCESS, rc,szSQLFREECONNECT);
  4244.             }
  4245.         }
  4246.  
  4247. } //TestSQLBrowseConnect()
  4248.  
  4249.  
  4250. //-----------------------------------------------------------------------
  4251. //      Function:               TestSQLDataSources
  4252. //-----------------------------------------------------------------------
  4253.  
  4254. void  PASCAL TestSQLDataSources()
  4255. {
  4256.     RETCODE rc=SQL_SUCCESS;
  4257.  
  4258.     if (!Supported( SQL_API_SQLDATASOURCES))
  4259.         {
  4260.         rc = SQLDataSources(henv, SQL_FETCH_FIRST, NULL, 0, NULL, NULL, 0, NULL);
  4261.     
  4262.         if(!FindError(SQL_HANDLE_ENV,szIM001))
  4263.             DISPLAYERROR(TEXT("SQLDataSources"), szNotSupported);
  4264.     
  4265.         RETCHECK(SQL_ERROR, rc,TEXT("SQLDataSources"));
  4266.         } 
  4267.     else 
  4268.         {
  4269.         rc = SQLDataSources(henv, SQL_FETCH_FIRST, NULL, 0, NULL, NULL, 0, NULL);
  4270.         RETCHECK(SQL_SUCCESS, rc,TEXT("SQLDataSources"));
  4271.         }
  4272.  
  4273. } //TestSQLDataSources()
  4274.  
  4275.  
  4276. //-----------------------------------------------------------------------
  4277. //      Function:               TestSQLDataSources
  4278. //-----------------------------------------------------------------------
  4279.  
  4280. void  PASCAL TestSQLDrivers()
  4281. {
  4282.     RETCODE rc=SQL_SUCCESS;
  4283.  
  4284.     if(!Supported( SQL_API_SQLDRIVERS)) 
  4285.         {
  4286.         rc = SQLDrivers(henv, SQL_FETCH_FIRST, NULL, 0, NULL, NULL, 0, NULL);
  4287.         if(!FindError(SQL_HANDLE_ENV,szIM001))
  4288.             DISPLAYERROR(TEXT("SQLDrivers"), szNotSupported);
  4289.         RETCHECK(SQL_ERROR, rc,TEXT("SQLDataSources"));
  4290.         }
  4291.     else
  4292.         {
  4293.         rc = SQLDrivers(henv, SQL_FETCH_FIRST, NULL, 0, NULL, NULL, 0, NULL);
  4294.         if(rc != SQL_SUCCESS)
  4295.             RETCHECK(SQL_SUCCESS_WITH_INFO, rc,TEXT("SQLDrivers"));
  4296.         }
  4297.  
  4298. } //TestSQLDrivers()
  4299.  
  4300.  
  4301. //-----------------------------------------------------------------------
  4302. //      Function:               TestSQLMoreResults
  4303. //-----------------------------------------------------------------------
  4304.  
  4305. void  PASCAL TestSQLMoreResults(QTSTRUCT  *lpqt)
  4306. {
  4307.     RETCODE rc=SQL_SUCCESS;
  4308.  
  4309.     if(!Supported( SQL_API_SQLMORERESULTS)) 
  4310.         {
  4311.         SelectFromTable(lpqt);
  4312.  
  4313.         rc = SQLMoreResults(hstmt);
  4314.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4315.             DISPLAYERROR(TEXT("SQLMoreResults"), szNotSupported);
  4316.         RETCHECK(SQL_ERROR, rc,TEXT("SQLMoreResults"));
  4317.         }
  4318.     else
  4319.         {
  4320.         SelectFromTable(lpqt);
  4321.  
  4322.         rc = SQLMoreResults(hstmt);
  4323.         RETCHECK(SQL_NO_DATA_FOUND, rc,TEXT("SQLMoreResults"));
  4324.         }
  4325.  
  4326.     FreeStmt(SQL_CLOSE);
  4327.  
  4328. } //TestSQLMoreResults()
  4329.  
  4330.  
  4331. //-----------------------------------------------------------------------
  4332. //      Function:               TestSQLMoreResults
  4333. //-----------------------------------------------------------------------
  4334.  
  4335. void  PASCAL TestSQLNativeSQL(QTSTRUCT  *lpqt)
  4336. {
  4337.     RETCODE    rc=SQL_SUCCESS;
  4338.     TCHAR        szQuery[XLARGEBUFF];
  4339.     
  4340.     wsprintf(szQuery,TEXT("select * from %s were 0 > 1"),lpqt->szTableName);
  4341.  
  4342.     if(!Supported( SQL_API_SQLNATIVESQL))
  4343.         {
  4344.         rc = SQLNativeSql(hdbc, szQuery, SQL_NTS, NULL, 0, NULL);
  4345.         if(!FindError(SQL_HANDLE_DBC,szIM001))
  4346.             DISPLAYERROR(TEXT("SQLNativeSql"), szNotSupported);
  4347.         RETCHECK(SQL_ERROR, rc,TEXT("SQLNativeSql"));
  4348.         }
  4349.     else 
  4350.         {
  4351.         rc = SQLNativeSql(hdbc, szQuery, SQL_NTS, NULL, 0, NULL);
  4352.         RETCHECK(SQL_SUCCESS, rc,TEXT("SQLNativeSql"));
  4353.         }
  4354.  
  4355.     FreeStmt(SQL_CLOSE);
  4356.     
  4357. } //TestSQLNativeSQL()
  4358.  
  4359.  
  4360. //-----------------------------------------------------------------------
  4361. //      Function:               TestSQLDescribeParam
  4362. //-----------------------------------------------------------------------
  4363.  
  4364. void  PASCAL TestSQLDescribeParam(QTSTRUCT  *lpqt)
  4365. {
  4366.     RETCODE rc=SQL_SUCCESS;
  4367.  
  4368.     rc = SQLPrepare(hstmt, lpqt->szParamQuery, SQL_NTS);
  4369.     RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE);
  4370.  
  4371.     if(!Supported( SQL_API_SQLDESCRIBEPARAM)) 
  4372.         {
  4373.         rc = SQLPrepare(hstmt, lpqt->szParamQuery, SQL_NTS);
  4374.         RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE);
  4375.         rc = SQLDescribeParam(hstmt, 1, NULL, NULL, NULL, NULL);
  4376.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4377.             DISPLAYERROR(szSQLDESCRIBEPARAM, szNotSupported);
  4378.         RETCHECK(SQL_ERROR, rc,szSQLDESCRIBEPARAM);
  4379.         }
  4380.     else
  4381.         {
  4382.         rc = SQLPrepare(hstmt, lpqt->szParamQuery, SQL_NTS);
  4383.         RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE);
  4384.         rc = SQLDescribeParam(hstmt, 1, NULL, NULL, NULL, NULL);
  4385.         RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBEPARAM);
  4386.         }
  4387.  
  4388.         FreeStmt(SQL_CLOSE);
  4389.  
  4390. } //TestSQLDescribeParam()
  4391.  
  4392.  
  4393.  
  4394. //-----------------------------------------------------------------------
  4395. //      Function:               TestSQLNumParams
  4396. //-----------------------------------------------------------------------
  4397.  
  4398. void  PASCAL TestSQLNumParams(QTSTRUCT  *lpqt)
  4399. {
  4400.     RETCODE rc=SQL_SUCCESS;
  4401.  
  4402.     rc = SQLPrepare(hstmt, lpqt->szParamQuery, SQL_NTS);
  4403.     RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE);
  4404.  
  4405.     if(!Supported( SQL_API_SQLNUMPARAMS)) 
  4406.         {
  4407.         rc = SQLNumParams(hstmt, NULL);
  4408.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4409.             DISPLAYERROR(szSQLNUMPARAMS, szNotSupported);
  4410.         RETCHECK(SQL_ERROR, rc,szSQLNUMPARAMS);
  4411.         }
  4412.     else
  4413.         {
  4414.         rc = SQLNumParams(hstmt, NULL);
  4415.         RETCHECK(SQL_SUCCESS, rc,szSQLNUMPARAMS);
  4416.         }
  4417.  
  4418.     FreeStmt(SQL_CLOSE);
  4419.  
  4420. } //TestSQLNumParams()
  4421.  
  4422.  
  4423.  
  4424.  
  4425.  
  4426. //-----------------------------------------------------------------------
  4427. //      Function:               TestSQLParamOptions
  4428. //-----------------------------------------------------------------------
  4429.  
  4430. void  PASCAL TestSQLParamOptions(QTSTRUCT *lpqt)
  4431. {
  4432.     RETCODE rc=SQL_SUCCESS;
  4433.  
  4434.     rc = SQLPrepare(hstmt, lpqt->szParamQuery, SQL_NTS);
  4435.     RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE);
  4436.  
  4437.     if(!Supported( SQL_API_SQLPARAMOPTIONS)) 
  4438.         {
  4439.         rc = SQLParamOptions(hstmt, 1, NULL);
  4440.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4441.             DISPLAYERROR(szSQLPARAMOPTIONS, szNotSupported);
  4442.         RETCHECK(SQL_ERROR, rc,szSQLPARAMOPTIONS);
  4443.         }
  4444.     else
  4445.         {
  4446.         rc = SQLParamOptions(hstmt, 1, NULL);
  4447.         RETCHECK(SQL_SUCCESS, rc,szSQLPARAMOPTIONS);
  4448.         }
  4449.  
  4450.     FreeStmt(SQL_CLOSE);
  4451.  
  4452. } //TestSQLParamOptions()
  4453.  
  4454.  
  4455.  
  4456.  
  4457. //-----------------------------------------------------------------------
  4458. //      Function:               TestSQLPrimaryKeys
  4459. //-----------------------------------------------------------------------
  4460.  
  4461. void  PASCAL TestSQLPrimaryKeys(QTSTRUCT *lpqt)
  4462. {
  4463.     RETCODE rc=SQL_SUCCESS;
  4464.  
  4465.     if (!Supported( SQL_API_SQLPRIMARYKEYS))
  4466.         {
  4467.         rc = SQLPrimaryKeys(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS);
  4468.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4469.             DISPLAYERROR(szSQLPRIMARYKEYS, szNotSupported);
  4470.         RETCHECK(SQL_ERROR, rc,szSQLPRIMARYKEYS);
  4471.         }
  4472.     else
  4473.         {
  4474.         rc = SQLPrimaryKeys(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS);
  4475.         RETCHECK(SQL_SUCCESS, rc,szSQLPRIMARYKEYS);
  4476.         while(rc == SQL_SUCCESS) 
  4477.             rc = SQLFetch(hstmt);
  4478.  
  4479.         RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH);
  4480.  
  4481.         FreeStmt(SQL_CLOSE);
  4482.  
  4483.         }
  4484.  
  4485. } //TestSQLPrimaryKeys()
  4486.  
  4487.  
  4488.  
  4489. //-----------------------------------------------------------------------
  4490. //      Function:               TestSQLProcedureColumns
  4491. //-----------------------------------------------------------------------
  4492.  
  4493. void  PASCAL TestSQLProcedureColumns(QTSTRUCT  *lpqt)
  4494. {
  4495.     RETCODE rc=SQL_SUCCESS;
  4496.  
  4497.     if(!Supported( SQL_API_SQLPROCEDURECOLUMNS)) 
  4498.         {
  4499.         rc = SQLProcedureColumns(hstmt, NULL, 0, NULL, 0, NULL, 0, NULL, 0);
  4500.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4501.             DISPLAYERROR(TEXT("SQLProcedureColumns"), szNotSupported);
  4502.         RETCHECK(SQL_ERROR, rc,TEXT("SQLProcedureColumns"));
  4503.         }
  4504.     else 
  4505.         {
  4506.         rc = SQLProcedureColumns(hstmt, NULL, 0, NULL, 0, NULL, 0, NULL, 0);
  4507.         RETCHECK(SQL_SUCCESS, rc,TEXT("SQLProcedureColumns"));
  4508.         while(rc == SQL_SUCCESS)
  4509.             rc = SQLFetch(hstmt);
  4510.  
  4511.         RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH);
  4512.  
  4513.         FreeStmt(SQL_CLOSE);
  4514.         }
  4515.  
  4516. } //TestSQLProcedureColumns()
  4517.  
  4518.  
  4519.  
  4520. //-----------------------------------------------------------------------
  4521. //      Function:               TestSQLProcedures
  4522. //-----------------------------------------------------------------------
  4523.  
  4524. void  PASCAL TestSQLProcedures()
  4525. {
  4526.     RETCODE rc=SQL_SUCCESS;
  4527.  
  4528.     if(!Supported( SQL_API_SQLPROCEDURES)) 
  4529.         {
  4530.         rc = SQLProcedures(hstmt, NULL, 0, NULL, 0, NULL, 0);
  4531.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4532.             DISPLAYERROR(TEXT("SQLProcedures"), szNotSupported);
  4533.         RETCHECK(SQL_ERROR, rc,TEXT("SQLProcedures"));
  4534.         }
  4535.     else
  4536.         {
  4537.         rc = SQLProcedures(hstmt, NULL, 0, NULL, 0, NULL, 0);
  4538.         RETCHECK(SQL_SUCCESS, rc,TEXT("SQLProcedures"));
  4539.         while(rc == SQL_SUCCESS)
  4540.             rc = SQLFetch(hstmt);
  4541.         RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH);
  4542.  
  4543.         FreeStmt(SQL_CLOSE);
  4544.         }
  4545.  
  4546. } //TestSQLProcedures()
  4547.  
  4548.  
  4549. //-----------------------------------------------------------------------
  4550. //      Function:               TestSQLTablePrivileges
  4551. //-----------------------------------------------------------------------
  4552.  
  4553. void  PASCAL TestSQLTablePrivileges()
  4554. {
  4555.     RETCODE rc=SQL_SUCCESS;
  4556.  
  4557.     if(!Supported( SQL_API_SQLTABLEPRIVILEGES)) 
  4558.         {
  4559.         rc = SQLTablePrivileges(hstmt, NULL, 0, NULL, 0, NULL, 0);
  4560.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4561.             DISPLAYERROR(TEXT("SQLTablePrivileges"), szNotSupported);
  4562.         RETCHECK(SQL_ERROR, rc,TEXT("SQLTablePrivileges"));
  4563.         }
  4564.     else
  4565.         {
  4566.         rc = SQLTablePrivileges(hstmt, NULL, 0, NULL, 0, NULL, 0);
  4567.         RETCHECK(SQL_SUCCESS, rc,TEXT("SQLTablePrivileges"));
  4568.         while(rc == SQL_SUCCESS) 
  4569.             rc = SQLFetch(hstmt);
  4570.  
  4571.         RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH);
  4572.  
  4573.         FreeStmt(SQL_CLOSE);
  4574.         }
  4575.  
  4576. } //TestSQLTablePrivileges()
  4577.  
  4578.  
  4579.  
  4580. //-----------------------------------------------------------------------
  4581. //      Function:               TestSQLColumnPrivileges
  4582. //-----------------------------------------------------------------------
  4583.  
  4584. void  PASCAL TestSQLColumnPrivileges(QTSTRUCT  *lpqt)
  4585. {
  4586.     RETCODE rc=SQL_SUCCESS;
  4587.  
  4588.     if(!Supported( SQL_API_SQLCOLUMNPRIVILEGES)) 
  4589.         {
  4590.         rc = SQLColumnPrivileges(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS,
  4591.             NULL, 0);
  4592.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4593.             DISPLAYERROR(TEXT("SQLColummPrivileges"), szNotSupported);
  4594.         RETCHECK(SQL_ERROR, rc,TEXT("SQLColumnPrivileges"));
  4595.         } 
  4596.     else
  4597.         {
  4598.         rc = SQLColumnPrivileges(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS,
  4599.             NULL, 0);
  4600.         RETCHECK(SQL_SUCCESS, rc,TEXT("SQLColumnPrivileges"));
  4601.         while(rc == SQL_SUCCESS)
  4602.             rc = SQLFetch(hstmt);
  4603.     
  4604.         RETCHECK(SQL_NO_DATA_FOUND, rc,szSQLFETCH);
  4605.  
  4606.         FreeStmt(SQL_CLOSE);
  4607.         }
  4608.  
  4609. } // TestSQLColumnPrivileges()
  4610.  
  4611.  
  4612. //-----------------------------------------------------------------------
  4613. //      Function:               TestSQLSetScrollOptions
  4614. //-----------------------------------------------------------------------
  4615.  
  4616. void  PASCAL TestSQLSetScrollOptions()
  4617. {
  4618.     RETCODE    rc=SQL_SUCCESS;
  4619.     UWORD        i,
  4620.                 j;
  4621.     UDWORD    fSupportedOpt;
  4622.     UDWORD    fSupportedCon;
  4623.     TCHAR        szState[100]=TEXT(""),
  4624.                 szErrMsg[XLARGEBUFF]=TEXT("");
  4625.  
  4626.     FreeStmt(SQL_CLOSE);
  4627.  
  4628.     if(!Supported( SQL_API_SQLSETSCROLLOPTIONS)) 
  4629.         {
  4630.         rc = SQLSetScrollOptions(hstmt, SQL_CONCUR_READ_ONLY, SQL_SCROLL_FORWARD_ONLY,
  4631.             1);
  4632.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4633.             DISPLAYERROR(szSQLSETSCROLLOPTIONS, szNotSupported);
  4634.         RETCHECK(SQL_ERROR, rc,szSQLSETSCROLLOPTIONS);
  4635.         } 
  4636.     else
  4637.         {
  4638.         rc = SQLGetInfo(hdbc, SQL_SCROLL_CONCURRENCY, &fSupportedCon, 4, NULL);
  4639.         RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO);
  4640.         rc = SQLGetInfo(hdbc, SQL_SCROLL_OPTIONS, &fSupportedOpt, 4, NULL);
  4641.         RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO);
  4642.  
  4643.         for(i = 0; i < sizeof(OptionList) / sizeof(SUPPORTOPTINFO); i ++) 
  4644.             {
  4645.             for(j = 0; j < sizeof(ConcurList) / sizeof(SUPPORTCONCURINFO); j++) 
  4646.                 {
  4647.                 if(fSupportedOpt & OptionList[i].Support && fSupportedCon & ConcurList[j].Support) 
  4648.                     {
  4649.                     if(!((ConcurList[j].Option == SQL_CONCUR_VALUES) && ((lpSI->vCursorLib == 
  4650.                             SQL_CUR_USE_IF_NEEDED) || (lpSI->vCursorLib == SQL_CUR_USE_ODBC))))
  4651.                         {
  4652.                         rc = SQLSetScrollOptions(hstmt, ConcurList[j].Option,OptionList[i].Option, 1);
  4653.                         RETCHECK(SQL_SUCCESS, rc,szSQLSETSCROLLOPTIONS);
  4654.                         }
  4655.  
  4656.                     }
  4657.                 }
  4658.             }
  4659.         }
  4660.  
  4661.     FreeStmt(SQL_CLOSE);
  4662.  
  4663. } //TestSQLSetScrollOptions()
  4664.  
  4665.  
  4666. //-----------------------------------------------------------------------------
  4667. //    Function:  TestConnectAttr
  4668. //-----------------------------------------------------------------------------
  4669.  
  4670. VOID PASCAL TestConnectAttr(HDBC hdbc,SDWORD fAttribute, UDWORD rgbValue,LPTSTR lpAttr,BOOL fReadOnlyAttr)
  4671. {
  4672.     RETCODE    rc=SQL_SUCCESS;
  4673.     TCHAR        szBuff[LARGEBUFF]=TEXT("");
  4674.     UDWORD    pvParam=0;
  4675.     RETCODE    rcExp=fReadOnlyAttr ? SQL_ERROR : SQL_SUCCESS;
  4676.  
  4677.     rc = SQLSetConnectAttr(hdbc,fAttribute,(PTR)rgbValue,sizeof(rgbValue));
  4678.  
  4679.     if(!FindError(SQL_HANDLE_DBC,szHYC00))
  4680.     {
  4681.  
  4682.         RETCHECK(rcExp,rc,szSQLSETCONNECTATTR);
  4683.     
  4684.         rc = SQLGetConnectAttr(hdbc,fAttribute,&pvParam,sizeof(pvParam),NULL);
  4685.  
  4686.         if(!FindError(SQL_HANDLE_DBC,szHYC00))
  4687.         {
  4688.             RETCHECK(SQL_SUCCESS,rc,szSQLGETCONNECTATTR);
  4689.  
  4690.             if(!fReadOnlyAttr && (pvParam != rgbValue))
  4691.             {
  4692.                 wsprintf(szBuff,TEXT("%s returned incorrect value"),lpAttr);
  4693.                 DISPLAYERROR(szSQLGETCONNECTATTR,szBuff);
  4694.             }
  4695.         }
  4696.         else
  4697.             RETCHECK(SQL_ERROR,rc,szSQLGETCONNECTATTR);
  4698.     }
  4699.     else
  4700.         RETCHECK(SQL_ERROR,rc,szSQLSETCONNECTATTR); 
  4701.  
  4702. } //TestConnectAttr()
  4703.  
  4704.  
  4705. //-----------------------------------------------------------------------------
  4706. //    Function:  TestSQLSetConnectAttr
  4707. //             This function tests both SQLSetConnectAttr and SQLGetConnectAttr
  4708. //-----------------------------------------------------------------------------
  4709.  
  4710. void  PASCAL TestSQLSetConnectAttr()
  4711. {
  4712.     RETCODE rc = SQL_SUCCESS;
  4713.     UDWORD    pvParam;
  4714.     UWORD    rgbValue;
  4715.     BOOL    fSupportSetConnectAttr = TRUE;
  4716.     BOOL    fSupportGetConnectAttr = TRUE;
  4717.  
  4718.     //make sure these APIs are supported before testing
  4719.     if(!Supported(SQL_API_SQLSETCONNECTATTR))
  4720.         {
  4721.         rgbValue = SQL_MODE_READ_WRITE;
  4722.         fSupportSetConnectAttr = FALSE;
  4723.         rc = SQLSetConnectAttr(hdbc,SQL_ACCESS_MODE,&rgbValue,sizeof(rgbValue));
  4724.         if(!FindError(SQL_HANDLE_DBC,szIM001))
  4725.             DISPLAYERROR(szSQLSETCONNECTATTR,TEXT("did not return Not supported message"));
  4726.         RETCHECK(SQL_ERROR,rc,szSQLSETCONNECTATTR);
  4727.         }
  4728.  
  4729.     if(!Supported(SQL_API_SQLGETCONNECTATTR))
  4730.         {
  4731.         fSupportGetConnectAttr = FALSE;
  4732.         rc = SQLGetConnectAttr(hdbc,SQL_ACCESS_MODE,&pvParam,sizeof(pvParam),NULL);
  4733.         if(!FindError(SQL_HANDLE_DBC,szIM001))
  4734.             DISPLAYERROR(szSQLGETCONNECTATTR,TEXT("did not return Not supported message"));
  4735.         RETCHECK(SQL_ERROR,rc,szSQLGETCONNECTATTR);
  4736.         }
  4737.  
  4738.     if(fSupportSetConnectAttr && (!fSupportGetConnectAttr))
  4739.         {
  4740.         //test SQL_ACCESS_MODE
  4741.         rgbValue = SQL_MODE_READ_WRITE;
  4742.         rc = SQLSetConnectAttr(hdbc,SQL_ACCESS_MODE,&rgbValue,sizeof(rgbValue));
  4743.         if(!FindError(SQL_HANDLE_DBC,szHYC00))
  4744.             RETCHECK(SQL_SUCCESS,rc,szSQLSETCONNECTATTR);
  4745.         else
  4746.             RETCHECK(SQL_ERROR,rc,szSQLSETCONNECTATTR);
  4747.         //test SQL_AUTOCOMMIT        
  4748.         rgbValue = SQL_AUTOCOMMIT_ON;
  4749.         rc = SQLSetConnectAttr(hdbc,SQL_AUTOCOMMIT,&rgbValue,sizeof(rgbValue));
  4750.         if(!FindError(SQL_HANDLE_DBC,szHYC00))
  4751.             RETCHECK(SQL_SUCCESS,rc,szSQLSETCONNECTATTR);
  4752.         else
  4753.             RETCHECK(SQL_ERROR,rc,szSQLSETCONNECTATTR);
  4754.         //test SQL_LOGIN_TIMEOUT
  4755.         //the choice of 15 seconds for timeout is arbitrary
  4756.         rgbValue = 15;
  4757.         rc = SQLSetConnectAttr(hdbc,SQL_LOGIN_TIMEOUT,&rgbValue,sizeof(rgbValue));
  4758.         if(!FindError(SQL_HANDLE_DBC,szHYC00))
  4759.             RETCHECK(SQL_SUCCESS,rc,szSQLSETCONNECTATTR);
  4760.         else
  4761.             RETCHECK(SQL_ERROR,rc,szSQLSETCONNECTATTR);
  4762.         }
  4763.  
  4764.     if((!fSupportSetConnectAttr) && fSupportGetConnectAttr)
  4765.     {
  4766.         //test SQL_ACCESS_MODE
  4767.         rc = SQLGetConnectAttr(hdbc,SQL_ACCESS_MODE,&pvParam,sizeof(pvParam),NULL);
  4768.         if(!FindError(SQL_HANDLE_DBC,szHYC00))
  4769.             RETCHECK(SQL_SUCCESS,rc,szSQLGETCONNECTATTR);
  4770.         else
  4771.             RETCHECK(SQL_ERROR,rc,szSQLGETCONNECTATTR);
  4772.         //test SQL_AUTOCOMMIT        
  4773.         rc = SQLGetConnectAttr(hdbc,SQL_AUTOCOMMIT,&pvParam,sizeof(pvParam),NULL);
  4774.         if(!FindError(SQL_HANDLE_DBC,szHYC00))
  4775.             RETCHECK(SQL_SUCCESS,rc,szSQLGETCONNECTATTR);
  4776.         else
  4777.             RETCHECK(SQL_ERROR,rc,szSQLGETCONNECTATTR);
  4778.         //test SQL_LOGIN_TIMEOUT
  4779.         rc = SQLGetConnectAttr(hdbc,SQL_LOGIN_TIMEOUT,&pvParam,sizeof(pvParam),NULL);
  4780.         if(!FindError(SQL_HANDLE_DBC,szHYC00))
  4781.             RETCHECK(SQL_SUCCESS,rc,szSQLGETCONNECTATTR);
  4782.         else
  4783.             RETCHECK(SQL_ERROR,rc,szSQLGETCONNECTATTR);
  4784.         //SQL_ATTR_AUTO_IPD is a read-only attribute        
  4785.         rc = SQLGetConnectAttr(hdbc,SQL_ATTR_AUTO_IPD,&pvParam,sizeof(pvParam),NULL);
  4786.         if(!FindError(SQL_HANDLE_DBC,szHYC00))
  4787.             RETCHECK(SQL_SUCCESS,rc,szSQLGETCONNECTATTR);
  4788.         else
  4789.             RETCHECK(SQL_ERROR,rc,szSQLGETCONNECTATTR);
  4790.     }
  4791.  
  4792.     if(fSupportSetConnectAttr && fSupportGetConnectAttr)
  4793.     {
  4794.         
  4795.         //test SQL_ACCESS_MODE
  4796.         TestConnectAttr(hdbc,SQL_ACCESS_MODE,SQL_MODE_READ_WRITE,TEXT("SQL_ACCESS_MODE"),FALSE);
  4797.         
  4798.         //test SQL_AUTOCOMMIT        
  4799.         TestConnectAttr(hdbc,SQL_AUTOCOMMIT,SQL_AUTOCOMMIT_ON,TEXT("SQL_AUTOCOMMIT"),FALSE);
  4800.             
  4801.         //test SQL_LOGIN_TIMEOUT
  4802.         //the choice of 15 seconds for timeout is arbitrary
  4803.         TestConnectAttr(hdbc,SQL_LOGIN_TIMEOUT,15,TEXT("SQL_LOGIN_TIMEOUT"),FALSE);
  4804.  
  4805.         //SQL_ATTR_AUTO_IPD is a read-only attribute        
  4806.         TestConnectAttr(hdbc,SQL_ATTR_AUTO_IPD,15,TEXT("SQL_ATTR_AUTO_IPD"),TRUE);
  4807.     }
  4808.  
  4809. } //TestSQLSetConnectAttr()
  4810.  
  4811.  
  4812.  
  4813. //-----------------------------------------------------------------------------
  4814. //    Function:  TestSQLSetStmtAttr
  4815. //             This function tests both SQLSetStmtAttr and SQLGetStmtAttr
  4816. //-----------------------------------------------------------------------------
  4817.  
  4818. void  PASCAL TestSQLSetStmtAttr()
  4819. {
  4820.     RETCODE rc = SQL_SUCCESS, rc2= SQL_SUCCESS;
  4821.     UDWORD    pvParam;
  4822.     UWORD    rgbValue;
  4823.     BOOL    fSupportSetStmtAttr = TRUE;
  4824.     BOOL    fSupportGetStmtAttr = TRUE;
  4825.  
  4826.     //make sure these APIs are supported before testing
  4827.     if(!Supported(SQL_API_SQLSETSTMTATTR))
  4828.         {
  4829.         //the choice of 300 for SQL_MAX_LENGTH is arbitrary
  4830.         rgbValue = 300;
  4831.         fSupportSetStmtAttr = FALSE;
  4832.         rc = SQLSetStmtAttr(hstmt,SQL_MAX_LENGTH,&rgbValue,sizeof(rgbValue));
  4833.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4834.             DISPLAYERROR(szSQLSETSTMTATTR,TEXT("did not return Not supported message"));
  4835.         RETCHECK(SQL_ERROR,rc,szSQLSETSTMTATTR);
  4836.         }
  4837.  
  4838.     if(!Supported(SQL_API_SQLGETSTMTATTR))
  4839.         {
  4840.         fSupportGetStmtAttr = FALSE;
  4841.         rc = SQLGetStmtAttr(hstmt,SQL_MAX_LENGTH,&pvParam,sizeof(pvParam),NULL);
  4842.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  4843.             DISPLAYERROR(szSQLGETSTMTATTR,TEXT("did not return Not supported message"));
  4844.         RETCHECK(SQL_ERROR,rc,szSQLGETSTMTATTR);
  4845.         }
  4846.  
  4847.     if(fSupportSetStmtAttr && (!fSupportGetStmtAttr))
  4848.         {
  4849.         //test SQL_MAX_LENGTH
  4850.         rgbValue = 300;
  4851.         rc = SQLSetStmtAttr(hstmt,SQL_MAX_LENGTH,&rgbValue,sizeof(rgbValue));
  4852.         if(!FindError(SQL_HANDLE_STMT,szHYC00))
  4853.             RETCHECK(SQL_SUCCESS,rc,szSQLSETSTMTATTR);
  4854.         else
  4855.             RETCHECK(SQL_ERROR,rc,szSQLSETSTMTATTR);
  4856.         //test SQL_ATTR_METADATA_ID -- new in 3.0
  4857.         rgbValue = SQL_FALSE;
  4858.         rc = SQLSetStmtAttr(hstmt,SQL_ATTR_METADATA_ID,&rgbValue,sizeof(rgbValue));
  4859.         if(!FindError(SQL_HANDLE_STMT,szHYC00))
  4860.             RETCHECK(SQL_SUCCESS,rc,szSQLSETSTMTATTR);
  4861.         else
  4862.             RETCHECK(SQL_ERROR,rc,szSQLSETSTMTATTR);
  4863.         }
  4864.  
  4865.     if((!fSupportSetStmtAttr) && fSupportGetStmtAttr)
  4866.         {
  4867.         //test SQL_MAX_LENGTH
  4868.         rc = SQLGetStmtAttr(hstmt,SQL_MAX_LENGTH,&pvParam,sizeof(pvParam),NULL);
  4869.         if(!FindError(SQL_HANDLE_STMT,szHYC00))
  4870.             RETCHECK(SQL_SUCCESS,rc,szSQLGETSTMTATTR);
  4871.         else
  4872.             RETCHECK(SQL_ERROR,rc,szSQLGETSTMTATTR);
  4873.         //test SQL_ATTR_METADATA_ID -- new in 3.0
  4874.         rc = SQLGetStmtAttr(hstmt,SQL_ATTR_METADATA_ID,&pvParam,sizeof(pvParam),NULL);
  4875.         if(!FindError(SQL_HANDLE_STMT,szHYC00))
  4876.             RETCHECK(SQL_SUCCESS,rc,szSQLGETSTMTATTR);
  4877.         else
  4878.             RETCHECK(SQL_ERROR,rc,szSQLGETSTMTATTR);
  4879.         }
  4880.     
  4881.     if(fSupportSetStmtAttr && fSupportGetStmtAttr)
  4882.         {
  4883.         
  4884.         //test SQL_MAX_LENGTH
  4885.         rgbValue = 300;
  4886.         rc = SQLSetStmtAttr(hstmt,SQL_MAX_LENGTH,(PTR)rgbValue,sizeof(rgbValue));
  4887.         if(!FindError(SQL_HANDLE_STMT,szHYC00))
  4888.             {
  4889.             RETCHECK(SQL_SUCCESS,rc,szSQLSETSTMTATTR);
  4890.             rc = SQLGetStmtAttr(hstmt,SQL_MAX_LENGTH,&pvParam,sizeof(pvParam),NULL);
  4891.             if(!FindError(SQL_HANDLE_STMT,szHYC00))
  4892.                 {
  4893.                 RETCHECK(SQL_SUCCESS,rc,szSQLGETSTMTATTR);
  4894.                 if(pvParam != 300)
  4895.                     DISPLAYERROR(szSQLGETSTMTATTR,TEXT("SQL_MAX_LENGTH returned incorrect value"));
  4896.                 }
  4897.             else
  4898.                 RETCHECK(SQL_ERROR,rc,szSQLGETSTMTATTR);
  4899.             }
  4900.         else
  4901.             RETCHECK(SQL_ERROR,rc,szSQLSETSTMTATTR);
  4902.         
  4903.     
  4904.         //test SQL_ATTR_METADATA_ID -- new in 3.0
  4905.         rgbValue = SQL_FALSE;
  4906.         rc = SQLSetStmtAttr(hstmt,SQL_ATTR_METADATA_ID,(PTR)rgbValue,sizeof(rgbValue));
  4907.         if (!FindError(SQL_HANDLE_STMT,szHYC00) && !FindError(SQL_HANDLE_STMT,szHY092))
  4908.             RETCHECK(SQL_SUCCESS,rc,szSQLSETSTMTATTR);
  4909.  
  4910.         rc2 = SQLGetStmtAttr(hstmt,SQL_ATTR_METADATA_ID,&pvParam,sizeof(pvParam),NULL);
  4911.         if (!FindError(SQL_HANDLE_STMT,szHYC00) && !FindError(SQL_HANDLE_STMT,szHY092))
  4912.             RETCHECK(SQL_SUCCESS,rc,szSQLGETSTMTATTR);
  4913.  
  4914.         if (RC_SUCCESSFUL(rc) && RC_SUCCESSFUL(rc2) && pvParam != SQL_FALSE)
  4915.             DISPLAYERROR(szSQLGETSTMTATTR,TEXT("SQL_ATTR_METADATA_ID returned incorrect value"));
  4916.     }
  4917.  
  4918. } //TestSQLSetStmtAttr()
  4919.  
  4920. //--------------------------------------------------------------------------------
  4921. // FUNCTION:    TestOneThread
  4922. // PURPOSE:        This function allocates the statement handle, performs simple 
  4923. //                queries and deallocates the statement handle.  This function is called
  4924. //                by testthreading.
  4925. //--------------------------------------------------------------------------------
  4926. static int TestOneThread(THREAD_STRUCT *ptArg)
  4927. {
  4928.     HENV        henv0 = ptArg->henv;
  4929.     HDBC        hdbc0 = ptArg->hdbc;
  4930.     HSTMT        hstmt0 = NULL;
  4931.     //RETCODE    rc=SQL_SUCCESS;
  4932.  
  4933.     /* allocate new statment handle */
  4934.     if (RC_NOTSUCCESSFUL(SQLAllocHandle(SQL_HANDLE_STMT,hdbc0, &hstmt0)))
  4935.         return(FALSE);
  4936.  
  4937.     /* perform some simple catalog functions */
  4938.     if (RC_NOTSUCCESSFUL(SQLStatistics(hstmt0,NULL,SQL_NTS,NULL,SQL_NTS,NULL,SQL_NTS,SQL_INDEX_ALL,SQL_QUICK)))
  4939.         return(FALSE);
  4940.  
  4941.     if (RC_NOTSUCCESSFUL(SQLCloseCursor(hstmt0)))
  4942.         return(FALSE);
  4943.  
  4944.     /* Get some data */
  4945.     GetSomeData(hstmt0, ptArg->szTableName, TRUE,ptArg->rgFieldInfo);
  4946.  
  4947.     if (RC_NOTSUCCESSFUL(SQLGetTypeInfo(hstmt0,SQL_CHAR)))
  4948.         return(FALSE);
  4949.  
  4950.     // Cleanup
  4951.     if (RC_NOTSUCCESSFUL(SQLFreeHandle(SQL_HANDLE_STMT,hstmt0)))
  4952.         return(FALSE);
  4953.  
  4954.     return(TRUE);
  4955.  
  4956. } //end of TestOneThread
  4957.  
  4958. //--------------------------------------------------------------------------------
  4959. // FUNCTION:    ThreadLoop
  4960. // PURPOSE:        This is the main loop for the threads, and it's called by 
  4961. //                CreateThread() API.
  4962. //--------------------------------------------------------------------------------
  4963. DWORD WINAPI ThreadLoop(void *pArg)
  4964. {
  4965.  
  4966.     THREAD_STRUCT *ptArg = (THREAD_STRUCT *)pArg;
  4967.     int i;
  4968.     RETCODE    rc;
  4969.  
  4970.     for(i=0; i< NUM_THREAD; i++)
  4971.         TestOneThread(ptArg);
  4972.  
  4973.     // free connection handle for each thread
  4974.     rc=SQLDisconnect(ptArg->hdbc);
  4975.     RETCHECK(SQL_SUCCESS,rc,szSQLDISCONNECT);
  4976.     rc=SQLFreeHandle(SQL_HANDLE_DBC,ptArg->hdbc);
  4977.     RETCHECK(SQL_SUCCESS,rc,szSQLFREEHANDLE);
  4978.  
  4979.        return(0);
  4980. } //end of ThreadLoop
  4981.  
  4982.  
  4983. //-------------------------------------------------------------------------------
  4984. // FUNCTION:    TestThreading
  4985. // PURPOSE:        This function tests the multi-threading capabilities of the 
  4986. //                driver by creating multiple threads that connect to the same data
  4987. //                 source.  Once connected, each thread performs simple queries to 
  4988. //                test that the driver handles these queries successfully.
  4989. //                This function is to be called inside AutoTestFunc() in QuikTest.
  4990. //--------------------------------------------------------------------------------
  4991. void TestThreading(lpSERVERINFO lpSI,QTSTRUCT  *lpqt,FIELDINFO *rgFieldInfo)
  4992. {
  4993.     RETCODE rc=SQL_SUCCESS;
  4994.    THREAD_STRUCT *pArg;
  4995.    HANDLE hThread[NUM_THREAD];
  4996.     DWORD dwThreadId;
  4997.     UWORD i;
  4998.     HENV    henv1;
  4999.     HDBC    hdbc1;
  5000.     
  5001.  
  5002.     // allocate memory for the threads
  5003.     pArg = (THREAD_STRUCT *)AllocateMemory((NUM_THREAD) * sizeof(THREAD_STRUCT));
  5004.  
  5005.     if(!pArg)
  5006.     {
  5007.         szWrite(TEXT("\t\t\tMultiThreading Test interrupted due to error in memory allocation"), TRUE);
  5008.         return;
  5009.     }
  5010.     
  5011.     // only one environment handle will be needed for all threads
  5012.     rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv1);
  5013.     RETCHECK(SQL_SUCCESS, rc,szSQLALLOCHANDLE);
  5014.  
  5015.     // Set environment attribute, or we can't allocate connection
  5016.     rc = SQLSetEnvAttr(henv1, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3,
  5017.         SQL_IS_UINTEGER);
  5018.     RETCHECK(SQL_SUCCESS, rc,szSQLSETENVATTR);
  5019.  
  5020.     for (i=0; i < NUM_THREAD; i++ ) 
  5021.     {
  5022.         // allocate connection handle for each thread
  5023.         rc=SQLAllocHandle(SQL_HANDLE_DBC,henv1, &hdbc1);
  5024.         RETCHECK(SQL_SUCCESS, rc,szSQLALLOCHANDLE);
  5025.  
  5026.         // create string to be used in connecting
  5027.         wsprintf(lpqt->sz,TEXT("dsn=%s;uid=%s;pwd=%s;"),
  5028.         lpSI->szValidServer0,
  5029.         lpSI->szValidLogin0,
  5030.         lpSI->szValidPassword0);
  5031.  
  5032.         SQLDriverConnect(hdbc1, lpSI->hwnd, lpqt->sz,
  5033.         SQL_NTS, lpqt->buf, MAX_STRING_SIZE, NULL, SQL_DRIVER_COMPLETE);
  5034.  
  5035.         // initialize thread structure
  5036.         pArg[i].henv = henv1;
  5037.         pArg[i].hdbc = hdbc1;
  5038.         lstrcpy(pArg[i].szTableName, lpqt->szTableName);
  5039.         pArg[i].rgFieldInfo=rgFieldInfo[0];
  5040.  
  5041.         // start thread
  5042.         hThread[i]= CreateThread(NULL,
  5043.                             0,
  5044.                             ThreadLoop,
  5045.                             &pArg[i],
  5046.                             0,
  5047.                             &dwThreadId);
  5048.  
  5049.         if(hThread[i]==0)
  5050.         {
  5051.             DISPLAYERROR(TEXT("TestThread failed:"),TEXT("cannot create thread"));
  5052.             break;
  5053.         }
  5054.     }
  5055.  
  5056.     // wait for thread completion
  5057.     WaitForMultipleObjects(NUM_THREAD,hThread,TRUE,INFINITE);
  5058.  
  5059.     for(i=0; i<NUM_THREAD; i++ )
  5060.         CloseHandle(hThread[i]);
  5061.  
  5062.     SQLFreeHandle(SQL_HANDLE_ENV,henv1);
  5063.     if (pArg)
  5064.         ReleaseMemory(pArg);
  5065. }    //end of TestThreading()
  5066.  
  5067.  
  5068. //-----------------------------------------------------------------------
  5069. //      Function:               CreateDescRecord
  5070. //-----------------------------------------------------------------------
  5071. SWORD CreateDescRecord(SQLHDESC hdesc, SQLHSTMT hstmt, UWORD uwDescType)
  5072. {
  5073.     UDWORD cbColDef;
  5074.     SWORD swColCount;
  5075.     SQLRETURN rc;
  5076.     SWORD fType, fSQLType;
  5077.     SWORD ibScale;
  5078.     TCHAR rgBuf[100];
  5079.  
  5080.     switch(uwDescType) {
  5081.         case SQL_ATTR_APP_ROW_DESC:
  5082.             rc = SQLSetDescField(hdesc, 1, SQL_DESC_TYPE, (SQLPOINTER)SQL_C_DEFAULT,
  5083.                 SQL_IS_SMALLINT);
  5084.             ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD);
  5085.             
  5086.             if (SQL_SUCCEEDED(rc))
  5087.                 return 1;
  5088.  
  5089.             rc=SQLBindCol(hstmt, 1, SQL_C_TCHAR, rgBuf, sizeof(rgBuf), NULL);
  5090.             RETCHECK(SQL_SUCCESS, rc,szSQLBINDCOL);
  5091.             if (SQL_SUCCEEDED(rc))
  5092.                 return 1;    
  5093.             break;
  5094.         case SQL_ATTR_IMP_PARAM_DESC:
  5095.         case SQL_ATTR_APP_PARAM_DESC:
  5096.             // Select statement has already been done by this time
  5097.             rc=SQLDescribeCol(hstmt, 1, NULL, 0, NULL, &fSQLType, &cbColDef, 
  5098.                 &ibScale, NULL);
  5099.             RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBECOL);
  5100.             if (!SQL_SUCCEEDED(rc))
  5101.                 return 0;
  5102.  
  5103.             if (SQL_ATTR_APP_PARAM_DESC == uwDescType)
  5104.                 fType=SQL_C_TCHAR;
  5105.             else
  5106.                 fType=fSQLType;
  5107.  
  5108.             rc = SQLSetDescField(hdesc, 1, SQL_DESC_TYPE, (SQLPOINTER)fType,
  5109.                 SQL_IS_SMALLINT);
  5110.             ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD);
  5111.             
  5112.             if (SQL_SUCCEEDED(rc))
  5113.                 return 1;
  5114.  
  5115.             rc=SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_TCHAR,
  5116.                 fSQLType, cbColDef, ibScale, rgBuf, sizeof(rgBuf), NULL);
  5117.             RETCHECK(SQL_SUCCESS, rc,szSQLDESCRIBECOL);
  5118.             if (SQL_SUCCEEDED(rc))
  5119.                 return 1;
  5120.             break;
  5121.         case SQL_ATTR_IMP_ROW_DESC:
  5122.             // Quiktest has already done the select for us
  5123.             // Need to find out how many cols in result set
  5124.             rc=SQLNumResultCols(hstmt, &swColCount);
  5125.             if (SQL_SUCCEEDED(rc))
  5126.                 return(swColCount);
  5127.             break;
  5128.     }
  5129.     return 0;
  5130. }    //CreateDescRecord
  5131.  
  5132. //-----------------------------------------------------------------------
  5133. //      Function:               CheckDescOp
  5134. //-----------------------------------------------------------------------
  5135. void CheckDescOp(SQLHDESC hdesc, SQLRETURN rc, SQLUSMALLINT uwDescIndex,
  5136.     SQLSMALLINT swDescRecCount, SQLSMALLINT swDescRec, SQLUSMALLINT iDescField,
  5137.     SQLINTEGER swUpdateMode)
  5138. {
  5139.     TCHAR * pszAPI, szOp[10];
  5140.     SQLSMALLINT fValidOp;    // Descriptor types operation is valid for
  5141.  
  5142.     if (DESC_UPDATE_MODE_READ == swUpdateMode)
  5143.     {
  5144.         pszAPI=szSQLGETDESCFIELD;
  5145.         lstrcpy(szOp, TEXT("read"));
  5146.         fValidOp=rgDescInfo[iDescField].fGettable;
  5147.     }
  5148.     else
  5149.     {
  5150.         pszAPI=szSQLSETDESCFIELD;
  5151.         lstrcpy(szOp, TEXT("write"));
  5152.         fValidOp=rgDescInfo[iDescField].fSettable;
  5153.     }
  5154.  
  5155.     // If we're reading beyond the last record, expect SQL_NO_DATA.
  5156.     if (swDescRec > swDescRecCount && DESC_UPDATE_MODE_READ == swUpdateMode)
  5157.     {
  5158.         wsprintf(buf,TEXT("%s: Able to %s descriptor field %s in the %s beyond last record."),
  5159.                 pszAPI, szOp, rgDescInfo[iDescField].szDescFieldName, DescTypes[uwDescIndex].szDescName);
  5160.         ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_NO_DATA, rc, buf);
  5161.     }
  5162.     else
  5163.     {
  5164.         if (fValidOp & DescTypes[uwDescIndex].uwTypeMask)
  5165.         {
  5166.             wsprintf(buf,TEXT("%s: Unable to %s descriptor field %s in the %s"),
  5167.                     pszAPI, szOp, rgDescInfo[iDescField].szDescFieldName, DescTypes[uwDescIndex].szDescName);
  5168.             ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, buf);
  5169.         }
  5170.         else
  5171.         {
  5172.             wsprintf(buf,TEXT("%s: Able to %s descriptor field %s in the %s"),
  5173.                     pszAPI, szOp, rgDescInfo[iDescField].szDescFieldName, DescTypes[uwDescIndex].szDescName);
  5174.             ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_ERROR, rc, buf);
  5175.         }
  5176.     }
  5177. }
  5178.  
  5179. //-----------------------------------------------------------------------
  5180. //
  5181. // Function: CompareDescField
  5182. //
  5183. // Compares two fields from the given descriptor, or to rgDescInfo if hdesc2
  5184. // is NULL.  uwDescField contains the entry in rgDescInfo for the desired field 
  5185. //-----------------------------------------------------------------------
  5186.  
  5187. void CompareDescField(SQLHDESC hdesc1, SQLHDESC hdesc2, SQLUSMALLINT uwDescIndex,
  5188.     SQLSMALLINT swDescRec, SQLSMALLINT swDescRecCount, SQLUSMALLINT uwDescField,
  5189.     TCHAR * pszAPI)
  5190. {
  5191.     SQLRETURN rc;
  5192.      SQLTCHAR DescBuf2[MAX_DESC_BUF];
  5193.     SQLINTEGER cbValue2; 
  5194.  
  5195.     // Make sure we've got a valid descriptor handle for hdesc1
  5196.     // (hdesc2 is allowed to be NULL)
  5197.     if (SQL_NULL_HDESC == hdesc1) {
  5198.         wsprintf(buf,TEXT("\t\tCompareDescriptor: hdesc1 handle was null!"));
  5199.         DISPLAYERROR(pszAPI, buf);
  5200.         return;
  5201.     }
  5202.  
  5203.     // Read the value from hdesc1
  5204.     rc = SQLGetDescField(hdesc1, swDescRec, rgDescInfo[uwDescField].uwDescField,
  5205.         &DescBuf, sizeof(DescBuf), &cbValue);
  5206.  
  5207.     CheckDescOp(hdesc1, rc, uwDescIndex, swDescRecCount, swDescRec, uwDescField, DESC_UPDATE_MODE_READ);
  5208.  
  5209.     cbValue2=rgDescInfo[uwDescField].cbValue;
  5210.  
  5211.     // Get the value to compare to
  5212.     if (SQL_NULL_HDESC == hdesc2) {
  5213.  
  5214.         // Compare to rgDescInfo if it's settable
  5215.         if (rgDescInfo[uwDescField].fSettable & DescTypes[uwDescIndex].uwTypeMask) {
  5216.             
  5217.             // Copy the set value into DescBuf2.  For char fields size is 0
  5218.             // (unknown), and the new value is actually the pointer to the start
  5219.             // of the string.
  5220.             SQLPOINTER pNewvalue = &(rgDescInfo[uwDescField].NewValue);
  5221.             
  5222.             if (!rgDescInfo[uwDescField].size)
  5223.             {
  5224.                 pNewvalue = (SQLPOINTER)rgDescInfo[uwDescField].NewValue;
  5225.                 cbValue2    = (lstrlen(pNewvalue)+1) * sizeof(TCHAR); 
  5226.             }
  5227.  
  5228.             memcpy(&DescBuf2, pNewvalue, cbValue2);
  5229.         }
  5230.     }
  5231.     else {
  5232.  
  5233.         // Compare to hdesc2
  5234.         rc = SQLGetDescField(hdesc2, swDescRec, rgDescInfo[uwDescField].uwDescField,
  5235.             &DescBuf2, sizeof(DescBuf2), &cbValue);
  5236.  
  5237.         // Since hdesc2 is an unassociated hdesc, treat it as an ARD
  5238.         // (uwDescIndex=0)
  5239.         CheckDescOp(hdesc2, rc, 0, swDescRecCount, swDescRec, uwDescField, DESC_UPDATE_MODE_READ);
  5240.     }
  5241.  
  5242.     // Perform the compare if settable in source desc and settable in
  5243.     // target desc (application descriptors) when using hdesc2
  5244.     if (rgDescInfo[uwDescField].fSettable & DescTypes[uwDescIndex].uwTypeMask)
  5245.     {
  5246.         if (!hdesc2 || (rgDescInfo[uwDescField].fSettable & DESC_ARD))
  5247.         {
  5248.             // IPD field SQL_DESC_TYPE is settable for consitency check, but set
  5249.             // value can't be retrieved, so skip compare in this case
  5250.             if (SQL_ATTR_IMP_PARAM_DESC != DescTypes[uwDescIndex].uwDescType ||
  5251.                 SQL_DESC_DATA_PTR != rgDescInfo[uwDescField].uwDescField)
  5252.             {
  5253.                 if (memcmp(DescBuf, DescBuf2, cbValue2)) {
  5254.                     // Compare error, print message
  5255.                     wsprintf(buf,TEXT("Compare error in %s field %s"),
  5256.                         DescTypes[uwDescIndex].szDescName,rgDescInfo[uwDescField].szDescFieldName);
  5257.                     DISPLAYERROR(pszAPI, buf);
  5258.                 }
  5259.             }
  5260.         }
  5261.     }
  5262. }
  5263.  
  5264.  
  5265. //-----------------------------------------------------------------------
  5266. //
  5267. // Function:  CheckDescriptor
  5268. //
  5269. // Checks all fields in all records of given descriptor.  If swUpdateMode is
  5270. // DESC_UPDATE_MODE_READ then all fields are read, otherwise all updatable
  5271. // fields are written.
  5272. //-----------------------------------------------------------------------
  5273. void CheckDescriptor(SQLHDESC hdesc, SQLINTEGER swUpdateMode, SQLHSTMT hstmt, UWORD uwDescIndex)
  5274. {
  5275.      SQLINTEGER cbValue2;
  5276.     SQLSMALLINT swDescRec=0, swDescRecCount, swAdditionalRecs=0;
  5277.     SQLUSMALLINT iDescField, iStartField=0;
  5278.     SQLRETURN rc;
  5279.  
  5280.     // Get the descriptor record count.
  5281.     rc = SQLGetDescField(hdesc, 0, SQL_DESC_COUNT, &swDescRecCount,
  5282.         sizeof(swDescRecCount), &cbValue);
  5283.  
  5284.     if (SQL_SUCCESS == rc) {
  5285.  
  5286.         // In read mode, try to read one past last record
  5287.         if (swUpdateMode == DESC_UPDATE_MODE_READ)
  5288.             swAdditionalRecs=1;
  5289.  
  5290.         // Check all records, including header
  5291.         for (swDescRec=0; swDescRec <= swDescRecCount+swAdditionalRecs; swDescRec++) {
  5292.  
  5293.             // Check all fields
  5294.             for (iDescField=iStartField; iDescField < sizeof(rgDescInfo)/sizeof(rgDescInfo[0]); iDescField++) {
  5295.  
  5296.                 // If we've gone past the header fields, then break out of loop to check record fields
  5297.                 if (0 == swDescRec && !rgDescInfo[iDescField].fHeader) {
  5298.                     iStartField=iDescField;
  5299.                     break;
  5300.                 }
  5301.  
  5302.                 if (DESC_UPDATE_MODE_READ == swUpdateMode)
  5303.                 {
  5304.                     // Read from the field
  5305.                     rc = SQLGetDescField(hdesc, swDescRec, rgDescInfo[iDescField].uwDescField,
  5306.                         &DescBuf, sizeof(DescBuf), &cbValue);
  5307.                     
  5308.                     CheckDescOp(hdesc, rc, uwDescIndex, swDescRecCount, swDescRec, iDescField, swUpdateMode);
  5309.  
  5310.                     if (RC_SUCCESSFUL(rc))
  5311.                     {
  5312.                         // Compare cbValue with expected
  5313.                         cbValue2=rgDescInfo[iDescField].cbValue; // For most fields
  5314.  
  5315.                         if (!rgDescInfo[iDescField].size)
  5316.                             cbValue2 = lstrlen((LPTSTR)DescBuf);  // For string fields
  5317.  
  5318.                         // Make sure cbValue and cbValue2 agree
  5319.                         if (cbValue != cbValue2)
  5320.                         {
  5321.                             wsprintf(buf,TEXT("Compare error in %s field %s, expected")\
  5322.                                 TEXT(" StringLength %d, received %d"), DescTypes[uwDescIndex].szDescName,
  5323.                                 rgDescInfo[iDescField].szDescFieldName, cbValue2, cbValue);
  5324.                             DISPLAYERROR(szSQLGETDESCFIELD, buf);
  5325.                         }
  5326.                     }
  5327.                 }
  5328.                 else
  5329.                 {
  5330.                     // Write to the field.  For char fields size is 0 (unknown),
  5331.                     // so compute the length of the string
  5332.                     rc = SQLSetDescField(hdesc, swDescRec, rgDescInfo[iDescField].uwDescField,
  5333.                         (SQLPOINTER)rgDescInfo[iDescField].NewValue,
  5334.                         (rgDescInfo[iDescField].size) ? rgDescInfo[iDescField].size :
  5335.                         lstrlen((LPTSTR)rgDescInfo[iDescField].NewValue)*sizeof(TCHAR));
  5336.  
  5337.                     CheckDescOp(hdesc, rc, uwDescIndex, swDescRecCount, swDescRec, iDescField, swUpdateMode);
  5338.  
  5339.                     if (RC_SUCCESSFUL(rc))
  5340.                         CompareDescField(hdesc, NULL, uwDescIndex, swDescRec, swDescRecCount,iDescField, szSQLSETDESCFIELD);
  5341.                 }
  5342.             }
  5343.         }
  5344.     }
  5345.     else {
  5346.         // Unable to read record count from descriptor header, can't proceed
  5347.         wsprintf(buf,TEXT("\t\tUnable to read record count from descriptor header."));
  5348.         ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, buf);
  5349.     }
  5350. }
  5351.  
  5352. //-----------------------------------------------------------------------
  5353. //
  5354. // Function:  CompareDescriptor
  5355. //
  5356. // Compares two descriptors, or if hdesc2 is NULL compares hdesc1 to rgDescInfo
  5357. // updatable columns
  5358. //-----------------------------------------------------------------------
  5359.  
  5360. void CompareDescriptor(SQLHDESC hdesc1, SQLHDESC hdesc2, UWORD uwDescIndex, TCHAR * pszAPI)
  5361. {
  5362.      SQLSMALLINT swDescRec, swDescRecCount;
  5363.     SQLUSMALLINT iDescField, iStartField=0;
  5364.     SQLRETURN rc;
  5365.  
  5366.     // Make sure we've got a valid descriptor handle for hdesc1
  5367.     // (hdesc2 is allowed to be NULL)
  5368.     if (SQL_NULL_HDESC == hdesc1) {
  5369.         wsprintf(buf,TEXT("\t\thCompareDescriptor: hdesc1 handle was null!"));
  5370.         DISPLAYERROR(szSQLGETDESCFIELD, buf);
  5371.         return;
  5372.     }
  5373.  
  5374.     // Get the descriptor record count.
  5375.     rc = SQLGetDescField(hdesc1, 0, SQL_DESC_COUNT, &swDescRecCount,
  5376.         sizeof(swDescRecCount), &cbValue);
  5377.  
  5378.     if (SQL_SUCCESS == rc) {
  5379.  
  5380.         // Check all records, including header
  5381.         for (swDescRec=0; swDescRec <= swDescRecCount; swDescRec++) {
  5382.  
  5383.             // Check all fields
  5384.             for (iDescField=iStartField; iDescField < sizeof(rgDescInfo)/sizeof(rgDescInfo[0]); iDescField++) {
  5385.  
  5386.                 // If we've gone past the header fields, then break out of loop to check record fields
  5387.                 if (0 == swDescRec && !rgDescInfo[iDescField].fHeader) {
  5388.                     iStartField=iDescField;
  5389.                     break;
  5390.                 }
  5391.  
  5392.                 CompareDescField(hdesc1, hdesc2, uwDescIndex, swDescRec, swDescRecCount, iDescField, pszAPI);
  5393.             }
  5394.         }
  5395.     }
  5396.     else {
  5397.         // Unable to read record count from descriptor header, can't proceed
  5398.         wsprintf(buf,TEXT("\t\tUnable to read record count from descriptor header."));
  5399.         ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_SUCCESS, rc, buf);
  5400.     }
  5401. }
  5402.  
  5403.  
  5404. void CheckDescRecord(SQLHDESC hdesc, SQLSMALLINT swDescRec, SQLSMALLINT fType,
  5405.            SQLSMALLINT fSubType, SQLINTEGER cbLength, SQLSMALLINT ibPrecision, SQLSMALLINT ibScale,
  5406.            SQLPOINTER pData, SQLINTEGER *pcbValue, SQLINTEGER *pIndicator, SQLUSMALLINT iDescType)
  5407. {
  5408.     SQLINTEGER Length, * pIndicator2;
  5409.     PTR pDescPtr;
  5410.     SQLRETURN rc;
  5411.     SQLSMALLINT fType2, fSubType2, cbName, Precision, Scale, Nullable;
  5412.     TCHAR    szName[MAX_DESC_BUF]=TEXT("");
  5413.  
  5414.     // Write the record
  5415.     rc = SQLSetDescRec(hdesc, swDescRec, fType, fSubType, cbLength, ibPrecision, 
  5416.         ibScale, pData, pcbValue, pIndicator);
  5417.  
  5418.     // Can't set IRD, so it should error
  5419.     if (SQL_ATTR_IMP_ROW_DESC == DescTypes[iDescType].uwDescType)
  5420.         ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_ERROR, rc, szSQLSETDESCREC);
  5421.     else
  5422.     {
  5423.         wsprintf(buf,TEXT("%s: Unable to write record %d in %s"),
  5424.             szSQLSETDESCREC, swDescRec, DescTypes[iDescType].szDescName);
  5425.         ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, buf);
  5426.     }
  5427.  
  5428.     if (RC_SUCCESSFUL(rc))
  5429.     {
  5430.         // Read it again
  5431.         rc = SQLGetDescRec(hdesc, swDescRec, szName, sizeof(szName), &cbName, &fType2,
  5432.             &fSubType2, &Length, &Precision, &Scale, &Nullable);
  5433.  
  5434.         wsprintf(buf,TEXT("%s: Unable to read record %d in %s"),
  5435.             szSQLGETDESCREC, swDescRec, DescTypes[iDescType].szDescName);
  5436.         ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, buf);
  5437.  
  5438.         if (RC_SUCCESSFUL(rc))
  5439.         {
  5440.             // Compare values
  5441.             if (fType2 != fType)
  5442.                 DISPLAYERROR(szSQLSETDESCREC,TEXT("fType not set correctly"));
  5443.             
  5444.             if (Precision != ibPrecision)
  5445.                 DISPLAYERROR(szSQLSETDESCREC,TEXT("ibPrecision not set correctly"));
  5446.  
  5447.             switch(fType)
  5448.             {
  5449.                 case SQL_DECIMAL:
  5450.                 case SQL_NUMERIC:
  5451.                 case SQL_C_DOUBLE:
  5452.                 case SQL_C_FLOAT:
  5453.                     // Scale is only defined for NUMERIC or DECIMAL types
  5454.                     if (Scale != ibScale)
  5455.                         DISPLAYERROR(szSQLSETDESCREC,TEXT("ibScale not set correctly"));
  5456.                     break;
  5457.                 case SQL_DATETIME:
  5458.                 case SQL_INTEGER:
  5459.                     // Subtype is only valid for DATETIME or INTERVAL types
  5460.                     if (fSubType2 != fSubType)
  5461.                         DISPLAYERROR(szSQLSETDESCREC,TEXT("fSubType not set correctly"));
  5462.                     break;
  5463.             }
  5464.  
  5465.             // For application descriptors, compare the Length and get the
  5466.             // data ptr value to check for accuracy
  5467.             switch(DescTypes[iDescType].uwDescType)
  5468.             {
  5469.                 case SQL_ATTR_APP_ROW_DESC:
  5470.                 case SQL_ATTR_APP_PARAM_DESC:
  5471.  
  5472.                     if (Length != cbLength)
  5473.                         DISPLAYERROR(szSQLSETDESCREC,TEXT("cbLength not set correctly"));
  5474.  
  5475.                     rc = SQLGetDescField(hdesc, swDescRec, SQL_DESC_DATA_PTR,
  5476.                         &pDescPtr, sizeof(PTR), &cbValue);
  5477.                     ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, szSQLGETDESCFIELD);
  5478.  
  5479.                     if (pDescPtr != pData)
  5480.                         DISPLAYERROR(szSQLSETDESCREC,TEXT("rgbValue not set correctly"));
  5481.  
  5482.                     // Get the octet length ptr value and check for accuracy
  5483.                     rc = SQLGetDescField(hdesc, swDescRec, SQL_DESC_OCTET_LENGTH_PTR,
  5484.                         &pDescPtr, sizeof(PTR), &cbValue);
  5485.                     ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, szSQLGETDESCFIELD);
  5486.  
  5487.                     if (pDescPtr != pcbValue)
  5488.                         DISPLAYERROR(szSQLSETDESCREC,TEXT("cbValue not set correctly"));
  5489.  
  5490.                     rc = SQLGetDescField(hdesc, swDescRec, SQL_DESC_INDICATOR_PTR,
  5491.                         &pIndicator2, sizeof(PTR), &cbValue);
  5492.                     ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, szSQLGETDESCFIELD);
  5493.  
  5494.                     if (pIndicator2 != pIndicator)
  5495.                         DISPLAYERROR(szSQLSETDESCREC,TEXT("Indicator not set correctly"));
  5496.                     
  5497.                     break;
  5498.                 case SQL_ATTR_IMP_ROW_DESC:
  5499.                 case SQL_ATTR_IMP_PARAM_DESC:
  5500.                     break;
  5501.                 default:
  5502.                     DISPLAYERROR(szSQLSETDESCREC,TEXT("Unknown descriptor type."));
  5503.             }
  5504.         }
  5505.     }
  5506.  
  5507. }
  5508.  
  5509. SQLRETURN DescBindParameter(SQLHSTMT hstmt, SQLUSMALLINT ipar,
  5510.     SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType,
  5511.     SQLUINTEGER cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue,
  5512.     SQLINTEGER cbValueMax, SQLINTEGER  *pcbValue)
  5513. {
  5514.     SQLHDESC hdescAPD, hdescIPD;
  5515.     SQLRETURN rc;
  5516.  
  5517.     rc = SQLGetStmtAttr(hstmt, SQL_ATTR_APP_PARAM_DESC, &hdescAPD, sizeof(hdescAPD), NULL);  
  5518.     if (!RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR))
  5519.         return rc;
  5520.  
  5521.     rc = SQLGetStmtAttr(hstmt, SQL_ATTR_IMP_PARAM_DESC, &hdescIPD, sizeof(hdescIPD), NULL);  
  5522.     if (!RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR))
  5523.         return rc;
  5524.  
  5525.     // Parameter type
  5526.     rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_PARAMETER_TYPE, (SQLPOINTER)fParamType,
  5527.         SQL_IS_SMALLINT);        // Set ipar and fParamType for IPD
  5528.     if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5529.         return rc;
  5530.     
  5531.     // C type
  5532.     rc = SQLSetDescField(hdescAPD, ipar, SQL_DESC_CONCISE_TYPE, (SQLPOINTER)fCType,
  5533.         SQL_IS_SMALLINT);        // Set ipar and fCType of APD
  5534.     if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescAPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5535.         return rc;
  5536.  
  5537.     // Sql type
  5538.     rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_CONCISE_TYPE, (SQLPOINTER)fSqlType,
  5539.         SQL_IS_SMALLINT);        // Set fSqlType of IPD
  5540.     if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5541.         return rc;
  5542.  
  5543.     // Column Size (Length or Precision)
  5544.     if (fSqlType == SQL_CHAR ||
  5545.         fSqlType == SQL_VARCHAR ||
  5546.         fSqlType == SQL_LONGVARCHAR ||
  5547.         fSqlType == SQL_BINARY ||
  5548.         fSqlType == SQL_VARBINARY ||
  5549.         fSqlType == SQL_LONGVARBINARY ||
  5550.         fSqlType == SQL_TYPE_DATE ||
  5551.         fSqlType == SQL_TYPE_TIME ||
  5552.         fSqlType == SQL_TYPE_TIMESTAMP ||
  5553.         (fSqlType >= SQL_INTERVAL_YEAR &&
  5554.          fSqlType <= SQL_INTERVAL_MINUTE_TO_SECOND))
  5555.     {
  5556.         rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_LENGTH, (SQLPOINTER)cbColDef,
  5557.             SQL_IS_UINTEGER);        // Set cbColDef (Length) of IPD
  5558.         if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5559.             return rc;
  5560.     }
  5561.     else if (fSqlType == SQL_DECIMAL ||
  5562.              fSqlType == SQL_NUMERIC ||
  5563.              fSqlType == SQL_FLOAT ||
  5564.              fSqlType == SQL_REAL ||
  5565.              fSqlType == SQL_DOUBLE)
  5566.     {
  5567.         rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_PRECISION, (SQLPOINTER)cbColDef,
  5568.             SQL_IS_SMALLINT);        // Set cbColDef (Precision) of IPD
  5569.         if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5570.             return rc;
  5571.     }
  5572.  
  5573.     // Scale
  5574.     if (fSqlType == SQL_TYPE_DATE ||
  5575.         fSqlType == SQL_TYPE_TIME ||
  5576.         fSqlType == SQL_TYPE_TIMESTAMP ||
  5577.         (fSqlType >= SQL_INTERVAL_YEAR &&
  5578.          fSqlType <= SQL_INTERVAL_MINUTE_TO_SECOND))
  5579.     {
  5580.         switch(fSqlType)
  5581.         {
  5582.             case SQL_TYPE_TIME:
  5583.             case SQL_TYPE_TIMESTAMP:
  5584.             case SQL_INTERVAL_SECOND:
  5585.             case SQL_INTERVAL_DAY_TO_SECOND:
  5586.             case SQL_INTERVAL_HOUR_TO_SECOND:
  5587.             case SQL_INTERVAL_MINUTE_TO_SECOND:
  5588.                 rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_PRECISION, (SQLPOINTER)ibScale,
  5589.                     SQL_IS_SMALLINT);        // Set scale of IPD
  5590.                 if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5591.                     return rc;
  5592.                 break;
  5593.             default:
  5594.                 rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_PRECISION, (SQLPOINTER)0,
  5595.                     SQL_IS_SMALLINT);        // Set scale of IPD
  5596.                 if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5597.                     return rc;
  5598.         }
  5599.     }
  5600.     else
  5601.     {
  5602.         rc = SQLSetDescField(hdescIPD, ipar, SQL_DESC_SCALE, (SQLPOINTER)ibScale,
  5603.             SQL_IS_SMALLINT);        // Set scale of IPD
  5604.         if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescIPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5605.             return rc;
  5606.     }
  5607.  
  5608.     // cbValueMax
  5609.     rc = SQLSetDescField(hdescAPD, ipar, SQL_DESC_OCTET_LENGTH, (SQLPOINTER)cbValueMax,
  5610.         SQL_IS_INTEGER);        // Set cbValueMax of APD
  5611.     if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescAPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5612.         return rc;
  5613.  
  5614.     // pcbValue
  5615.     rc = SQLSetDescField(hdescAPD, ipar, SQL_DESC_OCTET_LENGTH_PTR, (SQLPOINTER)pcbValue,
  5616.         SQL_IS_POINTER);        // Set pcbValue/octet length
  5617.     if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescAPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5618.         return rc;
  5619.  
  5620.     rc = SQLSetDescField(hdescAPD, ipar, SQL_DESC_INDICATOR_PTR, (SQLPOINTER)pcbValue,
  5621.         SQL_IS_POINTER);        // Set pcbValue/indicator
  5622.     if (!ERRSHANDLE(SQL_HANDLE_DESC, hdescAPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5623.         return rc;
  5624.  
  5625.     // Data ptr
  5626.     rc = SQLSetDescField(hdescAPD, ipar, SQL_DESC_DATA_PTR, (SQLPOINTER)rgbValue,
  5627.         SQL_IS_POINTER);        // Set rgbValue
  5628.     ERRSHANDLE(SQL_HANDLE_DESC, hdescAPD, SQL_SUCCESS, rc,szSQLSETDESCFIELD);
  5629.  
  5630.     return rc;
  5631.  
  5632. }
  5633.  
  5634. SQLRETURN DescBindCol(SQLHSTMT hstmt, SQLSMALLINT icol,
  5635.            SQLSMALLINT fCType, SQLPOINTER rgbValue,
  5636.            SQLINTEGER cbValueMax, SQLINTEGER *pcbValue)
  5637. {
  5638.     SQLHDESC hdesc;
  5639.     SQLRETURN rc;
  5640.  
  5641.     rc = SQLGetStmtAttr(hstmt, SQL_ATTR_APP_ROW_DESC, &hdesc, sizeof(hdesc), NULL);  
  5642.     if (!RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR))
  5643.         return rc;
  5644.  
  5645.     rc = SQLSetDescField(hdesc, icol, SQL_DESC_CONCISE_TYPE, (SQLPOINTER)fCType,
  5646.         SQL_IS_SMALLINT);        // Set icol and fCType
  5647.     if (!ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5648.         return rc;
  5649.     
  5650.     rc = SQLSetDescField(hdesc, icol, SQL_DESC_OCTET_LENGTH, (SQLPOINTER)cbValueMax,
  5651.         SQL_IS_INTEGER);        // Set cbValueMax
  5652.     if (!ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5653.         return rc;
  5654.  
  5655.     rc = SQLSetDescField(hdesc, icol, SQL_DESC_OCTET_LENGTH_PTR, (SQLPOINTER)pcbValue,
  5656.         SQL_IS_POINTER);        // Set pcbValue/octet length
  5657.     if (!ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5658.         return rc;
  5659.  
  5660.     rc = SQLSetDescField(hdesc, icol, SQL_DESC_INDICATOR_PTR, (SQLPOINTER)pcbValue,
  5661.         SQL_IS_POINTER);        // Set pcbValue/indicator
  5662.     if (!ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD))
  5663.         return rc;
  5664.  
  5665.     rc = SQLSetDescField(hdesc, icol, SQL_DESC_DATA_PTR, (SQLPOINTER)rgbValue,
  5666.         SQL_IS_POINTER);        // Set rgbValue
  5667.     ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc,szSQLSETDESCFIELD);
  5668.  
  5669.     return rc;
  5670. }
  5671.  
  5672. //-----------------------------------------------------------------------
  5673. //      Function:               TestGetDescField
  5674. //-----------------------------------------------------------------------
  5675.  
  5676. void  PASCAL TestGetDescField(QTSTRUCT * lpqt)
  5677. {
  5678.     SQLRETURN rc=SQL_SUCCESS;
  5679.     SQLUSMALLINT iDescType;
  5680.  
  5681.     SQLHDESC hdesc1=NULL, hdesc2=NULL;
  5682.     PTR rgbValue=NULL;
  5683.     SQLSMALLINT swDescRecCount, swExpRecCount;
  5684.     SQLINTEGER cbValue;
  5685.     TCHAR    szName[MAX_DESC_BUF]=TEXT("");
  5686.     TCHAR    szQuery[XLARGEBUFF]=TEXT("");
  5687.  
  5688.     if (!Supported(SQL_API_SQLGETDESCFIELD))
  5689.     {
  5690.         // Allocate a default descriptor
  5691.         rc = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc);  
  5692.  
  5693.         if (RC_SUCCESSFUL(rc))
  5694.         {
  5695.              rc = SQLGetDescField(hdesc, 0, SQL_DESC_COUNT, &DescBuf, sizeof(DescBuf),
  5696.                 &cbValue);
  5697.  
  5698.             if(!FindError(SQL_HANDLE_DESC,szIM001))
  5699.                 DISPLAYERROR(szSQLGETDESCFIELD, szNotSupported);
  5700.             RETCHECK(SQL_ERROR, rc,szSQLGETDESCFIELD);
  5701.         }
  5702.     }
  5703.     else
  5704.     {
  5705.         // Make sure all parameters and columns are unbound
  5706.         ResetHstmt(&hstmt);
  5707.  
  5708.         // Perform a select stmt
  5709.         wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName);
  5710.         rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
  5711.         RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  5712.  
  5713.         // For each descriptor type
  5714.         for (iDescType=0; iDescType < sizeof(DescTypes)/sizeof(DescTypes[0]); iDescType++)
  5715.         {
  5716.  
  5717.             // Get the handle for the automatically allocated descriptor
  5718.             rc = SQLGetStmtAttr(hstmt, DescTypes[iDescType].uwDescType, &hdesc1, sizeof(hdesc1), &cbValue);  
  5719.             RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR);
  5720.  
  5721.             // Create a descriptor record so we have something to read besides header
  5722.             swExpRecCount=CreateDescRecord(hdesc1, hstmt, DescTypes[iDescType].uwDescType);
  5723.  
  5724.             // Get the count of descriptor records (iRecord ignored for header fields)
  5725.             rc = SQLGetDescField(hdesc1, 0, SQL_DESC_COUNT, &swDescRecCount,
  5726.                 sizeof(swDescRecCount), &cbValue);
  5727.  
  5728.             if (SQL_SUCCEEDED(rc)) 
  5729.             {
  5730.                 // Check count value for expected
  5731.                 if (swExpRecCount != swDescRecCount)
  5732.                 {
  5733.                     wsprintf(buf,TEXT("Expected record count %d, found %d"),
  5734.                         swExpRecCount, swDescRecCount);
  5735.                     DISPLAYERROR(szSQLGETDESCFIELD, buf);
  5736.                 }
  5737.  
  5738.                 CheckDescriptor(hdesc1, DESC_UPDATE_MODE_READ, hstmt, iDescType);
  5739.             }
  5740.             else
  5741.             {
  5742.                 // Unable to read record count from descriptor header, can't proceed
  5743.                 wsprintf(buf,TEXT("Unable to read record count from descriptor header for descriptor type %d"),
  5744.                     DescTypes[iDescType].szDescName);
  5745.                 ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_SUCCESS, rc, buf);
  5746.             }
  5747.         }
  5748.  
  5749.         rc=SQLCloseCursor(hstmt);
  5750.         RETCHECK(SQL_SUCCESS, rc,szSQLCLOSECURSOR);
  5751.     }
  5752.  
  5753.  
  5754. } // TestGetDescField()
  5755.  
  5756. //-----------------------------------------------------------------------
  5757. //      Function:               TestSetDescField
  5758. //-----------------------------------------------------------------------
  5759.  
  5760. void  PASCAL TestSetDescField(QTSTRUCT * lpqt)
  5761. {
  5762.     SQLRETURN rc=SQL_SUCCESS;
  5763.     SQLUSMALLINT iDescType;
  5764.  
  5765.     SQLHDESC hdesc1=NULL, hdesc2=NULL;
  5766.     PTR rgbValue=NULL;
  5767.     SQLSMALLINT swDescRecCount, swExpRecCount;
  5768.     SQLINTEGER cbValue;
  5769.     TCHAR    szName[MAX_DESC_BUF]=TEXT("");
  5770.     TCHAR    szQuery[XLARGEBUFF]=TEXT("");
  5771.  
  5772.  
  5773.     if (!Supported(SQL_API_SQLSETDESCFIELD))
  5774.     {
  5775.         // Allocate a default descriptor
  5776.         rc = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc);  
  5777.  
  5778.         if (RC_SUCCESSFUL(rc))
  5779.         {
  5780.             rc = SQLSetDescField(hdesc, 0, SQL_DESC_COUNT, &swDescRecCount,
  5781.                 sizeof(swDescRecCount));
  5782.  
  5783.             if(!FindError(SQL_HANDLE_DESC,szIM001))
  5784.                 DISPLAYERROR(szSQLSETDESCFIELD, szNotSupported);
  5785.             RETCHECK(SQL_ERROR, rc,szSQLSETDESCFIELD);
  5786.         }
  5787.     }
  5788.     else
  5789.     {
  5790.         // Make sure all parameters and columns are unbound
  5791.         ResetHstmt(&hstmt);
  5792.         
  5793.         // Perform a select stmt
  5794.         wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName);
  5795.         rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
  5796.         RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  5797.  
  5798.         // For each descriptor type
  5799.         for (iDescType=0; iDescType < sizeof(DescTypes)/sizeof(DescTypes[0]); iDescType++)
  5800.         {
  5801.  
  5802.             // Get the handle for the automatically allocated descriptor
  5803.             rc = SQLGetStmtAttr(hstmt, DescTypes[iDescType].uwDescType, &hdesc1, sizeof(hdesc1), &cbValue);  
  5804.             RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR);
  5805.  
  5806.             // Create a descriptor record so we have something to read besides header
  5807.             swExpRecCount=CreateDescRecord(hdesc1, hstmt, DescTypes[iDescType].uwDescType);
  5808.  
  5809.             // Update all descriptor records to new values
  5810.             CheckDescriptor(hdesc1, DESC_UPDATE_MODE_WRITE, hstmt, iDescType);
  5811.  
  5812.             // Compare the descriptor with the update values
  5813.             // CompareDescriptor(hdesc1, NULL, iDescType, szSQLSETDESCFIELD);
  5814.         }
  5815.  
  5816.         ResetHstmt(&hstmt);
  5817.     }
  5818.  
  5819. } //TestSetDescField()
  5820.  
  5821. //-----------------------------------------------------------------------
  5822. //      Function:               TestGetDescRec
  5823. //-----------------------------------------------------------------------
  5824.  
  5825. void  PASCAL TestGetDescRec(QTSTRUCT * lpqt)
  5826. {
  5827.     SQLRETURN rc=SQL_SUCCESS;
  5828.     SQLUSMALLINT iDescType;
  5829.  
  5830.     SQLHDESC hdesc1=NULL, hdesc2=NULL;
  5831.     PTR rgbValue=NULL;
  5832.     SQLSMALLINT swDescRec, swDescRecCount, iRecord, cbNameMax, cbName, fType, fSubType,
  5833.         Precision, Scale, Nullable, swExpRecCount;
  5834.     SQLINTEGER Length, cbValue;
  5835.     TCHAR    szName[MAX_DESC_BUF]=TEXT("");
  5836.     TCHAR    szQuery[XLARGEBUFF]=TEXT("");
  5837.  
  5838.  
  5839.     if (!Supported(SQL_API_SQLGETDESCREC))
  5840.     {
  5841.         // Allocate a default descriptor
  5842.         rc = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc);  
  5843.  
  5844.         if (RC_SUCCESSFUL(rc))
  5845.         {
  5846.             rc = SQLGetDescRec(hdesc, iRecord, szName, cbNameMax, &cbName, &fType,
  5847.                 &fSubType, &Length, &Precision, &Scale, &Nullable);
  5848.  
  5849.             if(!FindError(SQL_HANDLE_DESC,szIM001))
  5850.                 DISPLAYERROR(szSQLGETDESCREC, szNotSupported);
  5851.             RETCHECK(SQL_ERROR, rc,szSQLGETDESCREC);
  5852.         }
  5853.     }
  5854.     else
  5855.     {
  5856.         // Make sure all parameters and columns are unbound
  5857.         ResetHstmt(&hstmt);
  5858.  
  5859.         // Turn on bookmarks so we can retrieve from record 0 of ARD
  5860.         rc = SQLSetStmtAttr(hstmt, SQL_ATTR_USE_BOOKMARKS, (SQLPOINTER)SQL_UB_ON, SQL_IS_INTEGER);
  5861.         RETCHECK(SQL_SUCCESS, rc,szSQLSETSTMTATTR);
  5862.         
  5863.         // Perform a select stmt
  5864.         wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName);
  5865.         rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
  5866.         RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  5867.  
  5868.         // For each descriptor type
  5869.         for (iDescType=0; iDescType < sizeof(DescTypes)/sizeof(DescTypes[0]); iDescType++)
  5870.         {
  5871.  
  5872.             // Get the handle for the automatically allocated descriptor
  5873.             rc = SQLGetStmtAttr(hstmt, DescTypes[iDescType].uwDescType, &hdesc1, sizeof(hdesc1), &cbValue);  
  5874.             RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR);
  5875.  
  5876.             // Create a descriptor record so we have something to read besides header
  5877.             swExpRecCount=CreateDescRecord(hdesc1, hstmt, DescTypes[iDescType].uwDescType);
  5878.  
  5879.             // Get the count of descriptor records
  5880.             // Count for automatically allocated descriptors is written in
  5881.             // SetDescField test.
  5882.             rc = SQLGetDescField(hdesc1, 0, SQL_DESC_COUNT, &swDescRecCount,
  5883.                 sizeof(swDescRecCount), &cbValue);
  5884.  
  5885.             if (SQL_SUCCESS == rc) 
  5886.             {
  5887.  
  5888.                 // For all descriptor records    
  5889.                 for (swDescRec=0; swDescRec <= swDescRecCount+1; swDescRec++)
  5890.                 {
  5891.                         // Read the record
  5892.                         rc = SQLGetDescRec(hdesc1, swDescRec, szName, sizeof(szName), &cbName, &fType,
  5893.                             &fSubType, &Length, &Precision, &Scale, &Nullable);
  5894.  
  5895.                         if (swDescRec <= swDescRecCount)
  5896.                         {
  5897.                             // Retrieving bookmark on IPD is an error
  5898.                             if (SQL_ATTR_IMP_PARAM_DESC == DescTypes[iDescType].uwDescType && 0 == swDescRec)
  5899.                             {
  5900.                                 wsprintf(buf,TEXT("%s: Able to read record %d from %s"),
  5901.                                     szSQLGETDESCREC, swDescRec, DescTypes[iDescType].szDescName);
  5902.                                 ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_ERROR, rc, buf);
  5903.                             }
  5904.                             else
  5905.                             {
  5906.                                 wsprintf(buf,TEXT("%s: Unable to read record %d from %s"),
  5907.                                     szSQLGETDESCREC, swDescRec, DescTypes[iDescType].szDescName);
  5908.                                 ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_SUCCESS, rc, buf);
  5909.                             }
  5910.                         }
  5911.                         else
  5912.                         {
  5913.                             wsprintf(buf,TEXT("%s: Did not receive SQL_NO_DATA reading record %d from %s"),
  5914.                                 szSQLGETDESCREC, swDescRec, DescTypes[iDescType].szDescName);
  5915.                             ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_NO_DATA, rc, buf);
  5916.                         }
  5917.                 }
  5918.             }
  5919.             else
  5920.             {
  5921.                 // Unable to read record count from descriptor header, can't proceed
  5922.                 wsprintf(buf,TEXT("\t\tUnable to read record count from descriptor header for %s"),
  5923.                     DescTypes[iDescType].szDescName);
  5924.                 ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_SUCCESS, rc, buf);
  5925.             }
  5926.         }
  5927.  
  5928.         rc=SQLCloseCursor(hstmt);
  5929.         RETCHECK(SQL_SUCCESS, rc,szSQLCLOSECURSOR);
  5930.  
  5931.     }
  5932.  
  5933. } //TestGetDescRec()
  5934.  
  5935. //-----------------------------------------------------------------------
  5936. //      Function:               TestSetDescRec
  5937. //-----------------------------------------------------------------------
  5938.  
  5939. void  PASCAL TestSetDescRec(QTSTRUCT * lpqt)
  5940. {
  5941.     SQLRETURN rc=SQL_SUCCESS;
  5942.     SQLINTEGER cbLength, cbValue, Indicator;
  5943.     SQLUSMALLINT iDescType;
  5944.  
  5945.     SQLHDESC hdesc1=NULL, hdesc2=NULL;
  5946.     PTR rgbValue=NULL;
  5947.     SQLSMALLINT swDescRec, swDescRecCount, swStartRec=1, iRecord, fType, fSubType,
  5948.         ibPrecision, ibScale;
  5949.     SQLSMALLINT swExpRecCount;
  5950.     TCHAR    szQuery[XLARGEBUFF]=TEXT("");
  5951.  
  5952.  
  5953.     if (!Supported(SQL_API_SQLSETDESCREC))
  5954.     {
  5955.         // Allocate a default descriptor
  5956.         rc = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc);  
  5957.  
  5958.         if (RC_SUCCESSFUL(rc))
  5959.         {
  5960.             rc = SQLSetDescRec(hdesc, iRecord, fType, fSubType, cbLength,
  5961.                 ibPrecision, ibScale, &DescBuf, &cbValue, &Indicator);
  5962.  
  5963.             if(!FindError(SQL_HANDLE_DESC,szIM001))
  5964.                 DISPLAYERROR(szSQLSETDESCREC, szNotSupported);
  5965.             RETCHECK(SQL_ERROR, rc,szSQLSETDESCREC);
  5966.         }
  5967.     }
  5968.     else
  5969.     {
  5970.         // Make sure all parameters and columns are unbound
  5971.         ResetHstmt(&hstmt);
  5972.         
  5973.         // Perform a select stmt
  5974.         wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName);
  5975.         rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
  5976.         RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  5977.  
  5978.         // If bookmarks are supported, then we want to try to set record 0
  5979.         rc = SQLSetStmtAttr(hstmt, SQL_ATTR_USE_BOOKMARKS,
  5980.             (PTR)SQL_UB_VARIABLE, SQL_IS_INTEGER);
  5981.         if (RC_SUCCESSFUL(rc))
  5982.             swStartRec=0;
  5983.  
  5984.         // For each descriptor type
  5985.         for (iDescType=0; iDescType < sizeof(DescTypes)/sizeof(DescTypes[0]); iDescType++)
  5986.         {
  5987.  
  5988.             // Get the handle for the automatically allocated descriptor
  5989.             rc = SQLGetStmtAttr(hstmt, DescTypes[iDescType].uwDescType, &hdesc1, sizeof(hdesc1), &cbValue);  
  5990.             RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR);
  5991.  
  5992.             // Create a descriptor record so we have something to read besides header
  5993.             swExpRecCount=CreateDescRecord(hdesc1, hstmt, DescTypes[iDescType].uwDescType);
  5994.  
  5995.             // Get the count of descriptor records
  5996.             rc = SQLGetDescField(hdesc1, 0, SQL_DESC_COUNT, &swDescRecCount,
  5997.                 sizeof(swDescRecCount), &cbValue);
  5998.  
  5999.             if (SQL_SUCCESS == rc) 
  6000.             {
  6001.  
  6002.                 // For all descriptor records    
  6003.                 for (swDescRec=swStartRec; swDescRec <= swDescRecCount; swDescRec++)
  6004.                 {
  6005.                     // Test with a DATETIME record so we can check the subtype field.
  6006.                     SQLINTEGER Indicator=0;
  6007.                     fType=SQL_DATETIME;
  6008.                     fSubType=SQL_CODE_TIMESTAMP;
  6009.                     cbLength=sizeof(TIMESTAMP_STRUCT);
  6010.                     ibPrecision=5;     // For DATETIME, SQL_CODE_DATE data
  6011.                                             // precision defaults to 0, but it implies it can be set otherwise.
  6012.                     ibScale=0;        // Only used for DECIMAL or NUMERIC types, otherwise undefined
  6013.  
  6014.                     CheckDescRecord(hdesc1, swDescRec, fType, fSubType, cbLength, ibPrecision, 
  6015.                         ibScale, &tsval, &cbValue, &Indicator, iDescType);                    
  6016.  
  6017.                     // Test with a numeric record to test scale
  6018.                     Indicator=0;
  6019.                     fType=SQL_NUMERIC;
  6020.                     fSubType=SQL_CODE_TIMESTAMP;
  6021.                     cbLength=sizeof(TIMESTAMP_STRUCT);
  6022.                     ibPrecision=5;     // For DATETIME, SQL_CODE_DATE data
  6023.                                             // precision defaults to 0, but it implies it can be set otherwise.
  6024.                     ibScale=0;        // Only used for DECIMAL or NUMERIC types, otherwise undefined
  6025.  
  6026.                     CheckDescRecord(hdesc1, swDescRec, fType, fSubType, cbLength, ibPrecision, 
  6027.                         ibScale, &tsval, &cbValue, &Indicator, iDescType);
  6028.                 }
  6029.             }
  6030.             else
  6031.             {
  6032.                 // Unable to read record count from descriptor header,
  6033.                 // can't proceed
  6034.                 wsprintf(buf,TEXT("\t\tUnable to read record count from descriptor header for  %s"),
  6035.                     DescTypes[iDescType].szDescName);
  6036.                 ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_SUCCESS, rc, buf);
  6037.             }
  6038.         }
  6039.         ResetHstmt(&hstmt);
  6040.     }
  6041.  
  6042. } //TestSetDescRec()
  6043.  
  6044. //-----------------------------------------------------------------------
  6045. //      Function:               TestCopyDesc
  6046. //-----------------------------------------------------------------------
  6047.  
  6048. void  PASCAL TestCopyDesc(QTSTRUCT * lpqt)
  6049. {
  6050.     SQLRETURN rc=SQL_SUCCESS;
  6051.     SQLUSMALLINT iDescType;
  6052.     SQLSMALLINT swExpRecCount;
  6053.  
  6054.     SQLHDESC hdesc1=NULL, hdesc2=NULL;
  6055.     PTR rgbValue=NULL;
  6056.     TCHAR    szName[MAX_DESC_BUF]=TEXT("");
  6057.     TCHAR    szQuery[XLARGEBUFF]=TEXT("");
  6058.  
  6059.  
  6060.     // Allocate a default descriptor
  6061.     rc = SQLAllocHandle(SQL_HANDLE_DESC, hdbc, &hdesc);  
  6062.  
  6063.     if (RC_SUCCESSFUL(rc))
  6064.     {
  6065.  
  6066.         if (!Supported(SQL_API_SQLCOPYDESC))
  6067.         {
  6068.             rc = SQLCopyDesc(hdesc, hdesc1);
  6069.  
  6070.             if(!FindError(SQL_HANDLE_DESC,szIM001))
  6071.                 DISPLAYERROR(szSQLCOPYDESC, szNotSupported);
  6072.             RETCHECK(SQL_ERROR, rc,szSQLCOPYDESC);
  6073.         }
  6074.         else
  6075.         {
  6076.             ResetHstmt(&hstmt);
  6077.             
  6078.             // Perform a select stmt
  6079.             wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName);
  6080.             rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
  6081.             RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  6082.  
  6083.             // For each descriptor type
  6084.             for (iDescType=0; iDescType < sizeof(DescTypes)/sizeof(DescTypes[0]); iDescType++)
  6085.             {
  6086.                 // Get the handle for the automatically allocated descriptor
  6087.                 rc = SQLGetStmtAttr(hstmt, DescTypes[iDescType].uwDescType, &hdesc1, sizeof(hdesc1), &cbValue);  
  6088.                 RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR);
  6089.  
  6090.                 // Create a descriptor record so we have something to read besides header
  6091.                 swExpRecCount=CreateDescRecord(hdesc1, hstmt, DescTypes[iDescType].uwDescType);
  6092.  
  6093.                 // Update all descriptor records to new values
  6094.                 CheckDescriptor(hdesc1, DESC_UPDATE_MODE_WRITE, hstmt, iDescType);
  6095.  
  6096.                 // Copy the descriptor to the newly allocated descriptor
  6097.                 rc = SQLCopyDesc(hdesc1, hdesc);
  6098.                 ERRSHANDLE(SQL_HANDLE_DESC, hdesc1, SQL_SUCCESS, rc, szSQLCOPYDESC);
  6099.                 ERRSHANDLE(SQL_HANDLE_DESC, hdesc, SQL_SUCCESS, rc, szSQLCOPYDESC);
  6100.  
  6101.                 // Compare each field in the copied descriptor to the original
  6102.                 if (RC_SUCCESSFUL(rc))
  6103.                     CompareDescriptor(hdesc1, hdesc, iDescType, szSQLCOPYDESC);
  6104.             }
  6105.  
  6106.             ResetHstmt(&hstmt);
  6107.         }
  6108.  
  6109.         // Free descriptor handle
  6110.         if (hdesc)
  6111.         {
  6112.             rc = SQLFreeHandle(SQL_HANDLE_DESC, hdesc); 
  6113.             RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE);
  6114.         }
  6115.     }
  6116.  
  6117. } //TestCopyDesc()
  6118.  
  6119.  
  6120. //-----------------------------------------------------------------------
  6121. //      Function:               TestDescDefaults
  6122. //-----------------------------------------------------------------------
  6123. void  PASCAL TestDescDefaults(QTSTRUCT * lpqt)
  6124. {
  6125.     SQLRETURN rc=SQL_SUCCESS;
  6126.      SQLINTEGER cbValue;
  6127.     SQLSMALLINT swDescRec;
  6128.     SQLUSMALLINT iDescField, iStartField=0, iDescType;
  6129.  
  6130.     if (Supported(SQL_API_SQLGETDESCFIELD))
  6131.     {
  6132.  
  6133.         // Reallocate hstmt to check defaults against
  6134.         ResetHstmt(&hstmt);
  6135.  
  6136.         // For each descriptor type
  6137.         for (iDescType=0; iDescType < sizeof(DescTypes)/sizeof(DescTypes[0]); iDescType++)
  6138.         {
  6139.             // Get the handle for the descriptor
  6140.             rc = SQLGetStmtAttr(hstmt, DescTypes[iDescType].uwDescType, &hdesc, sizeof(hdesc), NULL);  
  6141.             RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR);
  6142.  
  6143.             swDescRec=0;
  6144.  
  6145.             // For each descriptor field, read the value
  6146.             for (iDescField=iStartField; iDescField < sizeof(rgDescInfo)/sizeof(rgDescInfo[0]); iDescField++) {
  6147.  
  6148.                 // If we've gone past the header fields, then create a record and check record fields
  6149.                 if (0 == swDescRec && !rgDescInfo[iDescField].fHeader) {
  6150.                     iStartField=iDescField;
  6151.                     // Make sure we're not on the IRD, 'cause you can't modify an IRD
  6152.                     if (SQL_ATTR_IMP_ROW_DESC != DescTypes[iDescType].uwDescType)
  6153.                     {
  6154.                         // Create a record with all default values
  6155.                         rc = SQLSetDescField(hdesc, 0, SQL_DESC_COUNT, (SQLPOINTER)1,
  6156.                             SQL_IS_SMALLINT);
  6157.                         RETCHECK(SQL_SUCCESS, rc,szSQLSETDESCFIELD);
  6158.  
  6159.                         swDescRec++;
  6160.                     }
  6161.                     continue;
  6162.                 }
  6163.  
  6164.                 // If the field has a default value
  6165.                 if (rgDescInfo[iDescField].fDefault & DescTypes[iDescType].uwTypeMask)
  6166.                 {
  6167.                     // Read from the field
  6168.                     rc = SQLGetDescField(hdesc, swDescRec, rgDescInfo[iDescField].uwDescField,
  6169.                         &DescBuf, sizeof(DescBuf), &cbValue);
  6170.                     RETCHECK(SQL_SUCCESS, rc,szSQLGETDESCFIELD);
  6171.                     
  6172.                     if (RC_SUCCESSFUL(rc))
  6173.                     {
  6174.                         // Perform the compare
  6175.                         if (memcmp(DescBuf, &rgDescInfo[iDescField].DefaultVal, cbValue)) 
  6176.                         {
  6177.                             // Compare error, print message
  6178.                             wsprintf(buf,TEXT("Error in %s field %s default value"),
  6179.                                 DescTypes[iDescType].szDescName,rgDescInfo[iDescField].szDescFieldName);
  6180.                             DISPLAYERROR(szSQLGETDESCFIELD, buf);
  6181.                         }
  6182.                     }
  6183.                 }
  6184.             }
  6185.         }
  6186.     }
  6187. } // TestDescDefaults
  6188.  
  6189. //-----------------------------------------------------------------------
  6190. //      Function:               TestUseDesc
  6191. //-----------------------------------------------------------------------
  6192. void  PASCAL TestUseDesc(QTSTRUCT * lpqt, FIELDINFO  *rgFields)
  6193. {
  6194.     LPTSTR   pch=NULL;
  6195.     SDWORD crow=0;
  6196.     TCHAR    szQuery[XLARGEBUFF]=TEXT("");
  6197.     SQLRETURN rc;
  6198.     UWORD    row, icol, paramno;
  6199.     SWORD    ccol;
  6200.     TCHAR * rgbMemBuf=NULL, * rgbValue=NULL;
  6201.     SDWORD * pcbValueBuf=NULL, * pcbValue=NULL;
  6202.  
  6203.     if (Supported(SQL_API_SQLSETDESCFIELD))
  6204.     {
  6205.  
  6206.         // Test descriptor bindcol
  6207.         
  6208.         // Reallocate hstmt to set to defaults
  6209.         ResetHstmt(&hstmt);
  6210.         
  6211.         // Perform a select stmt
  6212.         wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName);
  6213.         rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
  6214.         RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  6215.  
  6216.         rc=SQLNumResultCols(hstmt, &ccol);
  6217.         RETCHECK(SQL_SUCCESS, rc, szSQLNUMRESULTCOLS);
  6218.  
  6219.         rc=SQLFreeStmt(hstmt, SQL_CLOSE); // Close the cursor so we can insert 
  6220.         RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT);
  6221.  
  6222.         rgbMemBuf=AllocateMemory(ccol*MAX_STRING_SIZE*sizeof(TCHAR));
  6223.  
  6224.         if (!rgbMemBuf)
  6225.         {
  6226.             DISPLAYERROR(TEXT("Simulate BindCol"),TEXT("Out of memory!"));
  6227.             goto ExitUseDesc;
  6228.         }
  6229.  
  6230.         pcbValueBuf=(SDWORD *)AllocateMemory(ccol*sizeof(SDWORD));
  6231.  
  6232.         if (!pcbValueBuf)
  6233.         {
  6234.             DISPLAYERROR(TEXT("Simulate BindCol"),TEXT("Out of memory!"));
  6235.             goto ExitUseDesc;
  6236.         }
  6237.  
  6238.         // Bind a parameter for each column in the result set using descriptors
  6239.         paramno=0;
  6240.         for (icol=1, rgbValue=rgbMemBuf, pcbValue=pcbValueBuf;
  6241.             icol <= ccol;
  6242.             icol++, rgbValue+=MAX_STRING_SIZE*sizeof(TCHAR), pcbValue++)
  6243.         {
  6244.             pch = qtMakeData(guwRowCount, icol-1, &rgFields[icol-1], rgbValue);
  6245.  
  6246.             // Field is not READ ONLY
  6247.             if(pch) 
  6248.             {
  6249.                  // Where row and column match and field is nullable, make NULL
  6250.                 if (icol == guwRowCount && rgFields[icol-1].nullable)
  6251.                     *pcbValue=SQL_NULL_DATA;
  6252.                 else
  6253.                     *pcbValue=SQL_NTS;
  6254.  
  6255.                 paramno++;
  6256. //                rc=SQLBindParameter(hstmt, paramno, SQL_PARAM_INPUT, SQL_C_CHAR, 
  6257.                 rc=DescBindParameter(hstmt, paramno, SQL_PARAM_INPUT, SQL_C_CHAR, 
  6258.                     rgFields[icol-1].wSQLType, rgFields[icol-1].precision,
  6259.                     rgFields[icol-1].scale, rgbValue, 0, pcbValue);
  6260.                 RETCHECK(SQL_SUCCESS, rc,TEXT("DescBindParameter"));
  6261.             }
  6262.         }
  6263.  
  6264.         // Insert the new row.  Note that the inserted row will be checked
  6265.         // for accuracy below.
  6266.         rc = SQLExecDirect(hstmt, szInsertStmt, SQL_NTS);
  6267.         ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_SUCCESS, rc, szSQLEXECDIRECT);
  6268.  
  6269.         if (RC_SUCCESSFUL(rc))
  6270.             guwRowCount++;
  6271.  
  6272.         // Perform the select stmt again
  6273.         wsprintf(szQuery,szSELECTSTAR,lpqt->szTableName);
  6274.         rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
  6275.         RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  6276.  
  6277.         // Bind all the columns to char
  6278.         for (icol=1, rgbValue=rgbMemBuf, pcbValue=pcbValueBuf;
  6279.             icol <= ccol;
  6280.             icol++, rgbValue+=MAX_STRING_SIZE*sizeof(TCHAR), pcbValue++)
  6281.         {
  6282.             // Bind to next column
  6283.             rc = DescBindCol(hstmt, icol, SQL_C_CHAR, rgbValue, MAX_STRING_SIZE*sizeof(TCHAR), pcbValue);
  6284. //            rc = SQLBindCol(hstmt, icol, SQL_C_CHAR, rgbValue, MAX_STRING_SIZE*sizeof(TCHAR), pcbValue);
  6285.             RETCHECK(SQL_SUCCESS, rc, TEXT("DescBindCol"));
  6286.         }
  6287.  
  6288.         // Fetch all the rows and check the bound value with MakeAData for
  6289.         // each column
  6290.         for (row=1; rc == SQL_SUCCESS; row++)
  6291.         {
  6292.             rc=SQLFetch(hstmt); // Will return SQL_NO_DATA after last row
  6293.  
  6294.             if (SQL_SUCCESS == rc)
  6295.             {
  6296.  
  6297.                 // Compare all the columns
  6298.                 for (icol=1, rgbValue=rgbMemBuf, pcbValue=pcbValueBuf;
  6299.                     icol <= ccol;
  6300.                     icol++, rgbValue+=MAX_STRING_SIZE*sizeof(TCHAR), pcbValue++)
  6301.                 {
  6302.  
  6303.                     CompareWithExpected(rgbValue, pcbValue, row, icol, rgFields);
  6304.                 }
  6305.             }
  6306.             else
  6307.                 ERRSHANDLE(SQL_HANDLE_STMT, hstmt, SQL_NO_DATA, rc, szSQLFETCH);
  6308.  
  6309.         }
  6310.  
  6311.     }
  6312.  
  6313. ExitUseDesc:
  6314.     rc=SQLFreeStmt(hstmt, SQL_CLOSE);
  6315.     RETCHECK(SQL_SUCCESS, rc,szSQLFREESTMT);
  6316.  
  6317.     if (rgbMemBuf)
  6318.         ReleaseMemory(rgbMemBuf);
  6319.     if (pcbValueBuf)
  6320.         ReleaseMemory(pcbValueBuf);
  6321.  
  6322.  
  6323. } // TestUseDesc
  6324.  
  6325. //-----------------------------------------------------------------------
  6326. //      Function:               TestEnvAttr
  6327. //
  6328. // Note:    Only one environment attribute (SQL_ATTR_OUTPUT_NTS) exists at this
  6329. //         time.  The default value is SQL_TRUE.
  6330. //
  6331. //    For the Environment attributes we assume support if DM version >= 3.00
  6332. //-----------------------------------------------------------------------
  6333.  
  6334. void  PASCAL TestEnvAttr()
  6335. {
  6336.     SQLINTEGER    sdwEnvAttr;
  6337.     SQLRETURN    rc;
  6338.     HENV            tshenv;
  6339.     BOOL            fSetSupported = Supported(SQL_API_SQLSETENVATTR),
  6340.                     fGetSupported = Supported(SQL_API_SQLGETENVATTR);
  6341.  
  6342.  
  6343.     //allocate an enviroment handle
  6344.     rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &tshenv);
  6345.     RETCHECK(SQL_SUCCESS, rc,szSQLALLOCHANDLE);
  6346.  
  6347.  
  6348.     //-------------------------------
  6349.     //-------- SQLSetEnvAttr --------
  6350.     //-------------------------------
  6351.     // Set to SQL_FALSE
  6352.     rc = SQLSetEnvAttr(tshenv, SQL_ATTR_ODBC_VERSION, (PTR)SQL_OV_ODBC3,
  6353.         SQL_IS_UINTEGER);
  6354.  
  6355.     if(!fSetSupported)
  6356.     {
  6357.         if (!FindError(SQL_HANDLE_ENV,szIM001))
  6358.             DISPLAYERROR(szSQLSETENVATTR, szNotSupported);
  6359.  
  6360.         RETCHECK(SQL_ERROR, rc,szSQLSETENVATTR);
  6361.     }
  6362.     else
  6363.         RETCHECK(SQL_SUCCESS, rc,szSQLSETENVATTR);
  6364.  
  6365.     if (RC_SUCCESSFUL(rc))
  6366.     {
  6367.         // Read it again
  6368.         rc = SQLGetEnvAttr(tshenv, SQL_ATTR_ODBC_VERSION, &sdwEnvAttr,
  6369.             sizeof(sdwEnvAttr), NULL);
  6370.  
  6371.         if(!fGetSupported)
  6372.         {
  6373.             if (!FindError(SQL_HANDLE_ENV,szIM001))
  6374.                 DISPLAYERROR(szSQLGETENVATTR, szNotSupported);
  6375.  
  6376.             RETCHECK(SQL_ERROR, rc,szSQLGETENVATTR);
  6377.         }
  6378.         else
  6379.             RETCHECK(SQL_SUCCESS, rc,szSQLGETENVATTR);
  6380.  
  6381.         if (RC_SUCCESSFUL(rc) && (SQL_OV_ODBC3 != sdwEnvAttr))
  6382.         {
  6383.             // New value wrong
  6384.             DISPLAYERROR(szSQLSETENVATTR,TEXT("Unable to set environment attribute SQL_ATTR_ODBC_VERSION to SQL_OV_ODBC3."));
  6385.         }
  6386.     }
  6387.  
  6388.     rc = SQLFreeHandle(SQL_HANDLE_ENV,tshenv);
  6389.     RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE);
  6390.  
  6391.     //-------------------------------
  6392.     //-------- SQLGetEnvAttr --------
  6393.     //-------------------------------
  6394.     rc = SQLAllocEnv(&tshenv);
  6395.     RETCHECK(SQL_SUCCESS, rc,szSQLALLOCENV);
  6396.  
  6397.     rc = SQLGetEnvAttr(tshenv, SQL_ATTR_ODBC_VERSION, &sdwEnvAttr,
  6398.         sizeof(sdwEnvAttr), NULL);
  6399.  
  6400.     if(!fGetSupported)
  6401.     {
  6402.         if (!FindError(SQL_HANDLE_ENV,szIM001))
  6403.             DISPLAYERROR(szSQLGETENVATTR, szNotSupported);
  6404.  
  6405.         RETCHECK(SQL_ERROR, rc,szSQLGETENVATTR);
  6406.     }
  6407.     else
  6408.         RETCHECK(SQL_SUCCESS, rc,szSQLGETENVATTR);
  6409.  
  6410.     
  6411.     if (RC_SUCCESSFUL(rc) && (SQL_OV_ODBC2 != sdwEnvAttr))
  6412.     {
  6413.         // Default value wrong
  6414.         DISPLAYERROR(szSQLGETENVATTR,TEXT("Value was not SQL_OV_ODBC3!"));
  6415.     }
  6416.  
  6417.  
  6418.     rc = SQLFreeHandle(SQL_HANDLE_ENV,tshenv);
  6419.     RETCHECK(SQL_SUCCESS, rc,szSQLFREEHANDLE);
  6420.  
  6421. } //TestEnvAttr()
  6422.  
  6423.  
  6424. //-----------------------------------------------------------------------
  6425. //    Function: GetRowCnt
  6426. //
  6427. //        Get the row count of the table lpqt->szTalbeName
  6428. //-----------------------------------------------------------------------
  6429. SWORD  PASCAL GetRowCnt(QTSTRUCT  *lpqt)
  6430. {
  6431.      SWORD         sRowCnt;
  6432.     RETCODE        rc;
  6433.  
  6434.     // free the statment handle for a fresh start
  6435.     FreeStmt(SQL_DROP);
  6436.  
  6437.     AllocHstmt();
  6438.  
  6439.     //get row count for the table
  6440.     wsprintf(lpqt->sz,TEXT("select count(*) from %s"), lpqt->szTableName);
  6441.  
  6442.     rc = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  6443.     RETCHECK(SQL_SUCCESS, rc,szSQLEXECDIRECT);
  6444.  
  6445.     rc = SQLFetch(hstmt);
  6446.     RETCHECK(SQL_SUCCESS, rc,szSQLFETCH);
  6447.  
  6448.     rc = SQLGetData(hstmt,1, SQL_C_SSHORT, &sRowCnt, sizeof(sRowCnt), NULL);
  6449.     RETCHECK(SQL_SUCCESS, rc,szSQLGETDATA);
  6450.  
  6451.     FreeStmt(SQL_CLOSE);
  6452.  
  6453.     return sRowCnt;
  6454. }//GetRowCount
  6455.  
  6456.  
  6457. //-----------------------------------------------------------------------
  6458. //    Function: InsertOneRow
  6459. //
  6460. //        Insert one row into the table.
  6461. //
  6462. //            lpqt:            temp place to hold data genrated
  6463. //            rgFields:    hold info about each data type in the dbs
  6464. //            cTypes;        the count of data types
  6465. //            lpd:            buffer used for SQLBindParam
  6466. //            cSeed;        the seed used to generate data
  6467. //            fFreeHsmt:    if the hstmt should be freed       
  6468. //
  6469. //        Return TRUE: the insertion was successful
  6470. //                 FALSE: otherwise
  6471. //-----------------------------------------------------------------------
  6472.                                           
  6473. BOOL  PASCAL InsertOneRow(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes,
  6474.                                         DSTRUCT  *lpd,UWORD cSeed,BOOL fFreeHstmt)
  6475. {
  6476.     RETCODE              rc;
  6477.     UWORD                w;
  6478.     UWORD                ind;
  6479.     LPTSTR                pch=NULL;
  6480.     SQLHDESC                hdesc;
  6481.    SQLSMALLINT          fParamType = SQL_PARAM_INPUT;
  6482.     TCHAR                    szDataItem[150];
  6483.  
  6484.  
  6485.     //prepare the insert statement
  6486.     rc = SQLPrepare(hstmt, szInsertStmt, SQL_NTS);
  6487.     RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE);
  6488.  
  6489.     //going through each data type, call SQLBindParam
  6490.     for(ind = 0, w = 0; ind < cTypes; ind++) 
  6491.     {
  6492.  
  6493.         //make data according to data type description in rgFields[], cSeed is the seed
  6494.         pch = qtMakeData(cSeed,ind,&rgFields[ind], szDataItem);
  6495.  
  6496.         //if the data type is READ_ONLY, skip
  6497.         if(!pch) 
  6498.             continue;
  6499.  
  6500.         //populate the NULL data
  6501.         if(*pch) 
  6502.         {
  6503.             lstrcpy(lpd[w].data, pch);
  6504.             lpd[w].cb = SQL_NTS;
  6505.         }
  6506.         else 
  6507.         {
  6508.             lstrcpy(lpd[w].data,TEXT(""));
  6509.             lpd[w].cb = SQL_NULL_DATA;
  6510.         }
  6511.  
  6512.         if (g_f3XDriver && Supported(SQL_API_SQLSETDESCFIELD))
  6513. //        if (0)    //DEBUG
  6514.         {
  6515.             //bind the data buffer in lpd[] to each column of the table
  6516.             rc = SQLBindParam(hstmt, (SQLSMALLINT)(w+1),SQL_C_TCHAR, rgFields[ind].wSQLType,
  6517.                                     rgFields[ind].precision, rgFields[ind].scale,
  6518.                                     &lpd[w].data, &lpd[w].cb);
  6519.             RETCHECK(SQL_SUCCESS, rc,szSQLBINDPARAM);
  6520.  
  6521.             if(rc!= SQL_SUCCESS)
  6522.                 return FALSE;
  6523.  
  6524.             //get the driver parameter descriptor handle
  6525.             rc = SQLGetStmtAttr(hstmt,SQL_ATTR_IMP_PARAM_DESC, &hdesc, sizeof(hdesc),NULL);
  6526.             RETCHECK(SQL_SUCCESS, rc,szSQLGETSTMTATTR);
  6527.             if(rc!= SQL_SUCCESS)
  6528.                 return FALSE;
  6529.  
  6530.             //set the parameter type field in the descriptor
  6531.             rc = SQLSetDescField(hdesc, (SQLSMALLINT)(w+1), SQL_DESC_PARAMETER_TYPE, 
  6532.                                         (PTR)fParamType, sizeof(fParamType));
  6533.             RETCHECK(SQL_SUCCESS, rc,szSQLSETDESCFIELD);
  6534.  
  6535.         }
  6536.         else
  6537.         {
  6538.             rc = SQLBindParameter(hstmt, (UWORD)(w+1),SQL_PARAM_INPUT,SQL_C_TCHAR, 
  6539.                             rgFields[ind].wSQLType,    rgFields[ind].precision, 
  6540.                             rgFields[ind].scale,&lpd[w].data, 100, &lpd[w].cb);
  6541.                 
  6542.             RETCHECK(SQL_SUCCESS, rc,szSQLBINDPARAMETER);
  6543.  
  6544.             if(rc!= SQL_SUCCESS)
  6545.                 return FALSE;
  6546.         }
  6547.  
  6548.  
  6549.         //go on to next column
  6550.         w++;
  6551.     }
  6552.  
  6553.     // insert a row 
  6554.     rc = SQLExecute(hstmt); 
  6555.     RETCHECK(SQL_SUCCESS, rc,szSQLEXECUTE);
  6556.     if(rc!= SQL_SUCCESS)
  6557.         return FALSE;
  6558.  
  6559.     //free the hstmt if required
  6560.     if(fFreeHstmt)
  6561.     {
  6562.         if (FreeStmt(SQL_CLOSE))
  6563.             return FALSE;
  6564.  
  6565.     }
  6566.  
  6567.     return TRUE;
  6568.  
  6569. }    //InsertOneRow
  6570.  
  6571. //-----------------------------------------------------------------------
  6572. //    Function: ExecEndTran
  6573. //
  6574. //        Execute EndTran statement, return the row count of the table
  6575. //-----------------------------------------------------------------------
  6576. SWORD  PASCAL ExecEndTran(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes,
  6577.                                 DSTRUCT  *lpd,SQLSMALLINT fHandleType, SQLSMALLINT fMode,
  6578.                                 UWORD cSeed)
  6579. {
  6580.           RETCODE rc;
  6581.  
  6582.         //does not free the hstmt
  6583.         if(!InsertOneRow(lpqt,rgFields,cTypes,lpd,cSeed, FALSE))
  6584.                 return (INSERT_FAIL);
  6585.  
  6586.         switch(fHandleType)
  6587.         {
  6588.             case SQL_HANDLE_ENV:
  6589.                 rc= SQLEndTran(fHandleType,henv,fMode);
  6590.                 break;
  6591.             case SQL_HANDLE_DBC:
  6592.                 rc= SQLEndTran(fHandleType,hdbc,fMode);
  6593.                 break;
  6594.             default:    
  6595.                 DISPLAYERROR(TEXT("ExecEndTran"),TEXT("Did not recieve correct handle type"));
  6596.                 break;
  6597.         }
  6598.         RETCHECK(SQL_SUCCESS, rc,szSQLENDTRAN);
  6599.  
  6600.         if (SQL_COMMIT == fMode && SQL_SUCCESS == rc)
  6601.             guwRowCount++;    // We inserted a row, increment global row count
  6602.  
  6603.         //free the hstmt handle
  6604.         FreeStmt(SQL_CLOSE);
  6605.  
  6606.         return(GetRowCnt(lpqt));
  6607. } //ExecEndTran
  6608.  
  6609. //-----------------------------------------------------------------------
  6610. //    Function: TestEndTran
  6611. //
  6612. //        Test the SQLEndTran for SDK 3.0
  6613. //-----------------------------------------------------------------------
  6614. void  PASCAL TestEndTran(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes,
  6615.                                         DSTRUCT  *lpd)
  6616. {
  6617.     SWORD                i;
  6618.     RETCODE             rc;
  6619.     SWORD                sTXN;
  6620.     SWORD                sRowCnt_Pre;
  6621.     SWORD                sRowCnt_Aft;
  6622.     SQLSMALLINT         fHandleType[]={SQL_HANDLE_ENV, SQL_HANDLE_DBC};
  6623.     SDWORD            cbValue=0;
  6624.  
  6625.     //check if transaction is supported
  6626.     rc = SQLGetInfo(hdbc, SQL_TXN_CAPABLE, &sTXN, sizeof(sTXN), NULL);
  6627.     RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO);
  6628.  
  6629.     //check both henv and hdbc handle
  6630.     for(i=0; i<=1; i++)
  6631.     { 
  6632.  
  6633.         //get the row count of the table
  6634.         sRowCnt_Pre = GetRowCnt(lpqt);
  6635.  
  6636.         //check if SQLEndTran is supported
  6637.         if(Supported(SQL_API_SQLENDTRAN))
  6638.         {
  6639.             if(sTXN != SQL_TC_NONE)
  6640.             {
  6641.                 //set the autocommit to off
  6642.                 SetConnectionAttributes(hdbc,SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
  6643.                 
  6644.                 //insert one row, and call SQLEndTran to roll back the transction
  6645.                 sRowCnt_Aft = ExecEndTran(lpqt,rgFields,cTypes,lpd,fHandleType[i],SQL_ROLLBACK,(UWORD)(guwRowCount));
  6646.                 
  6647.                 //the row count should be the same
  6648.                 if(sRowCnt_Aft != sRowCnt_Pre)
  6649.                     DISPLAYERROR(szSQLENDTRAN,TEXT("Did not Roll Back the insert transaction"));
  6650.             }
  6651.                 
  6652.             //insert one row, and call SQLEndTran to commit the transction
  6653.             sRowCnt_Aft = ExecEndTran(lpqt,rgFields,cTypes,lpd,fHandleType[i],SQL_COMMIT,(UWORD)(guwRowCount));
  6654.  
  6655.             //the row count should be increased by 1
  6656.             if(sRowCnt_Aft != (sRowCnt_Pre+1) )
  6657.                 DISPLAYERROR(szSQLENDTRAN,TEXT("Did not commit the insert transaction"));
  6658.  
  6659.             if( sTXN != SQL_TC_NONE)
  6660.             {
  6661.                 //set the autocommit to off
  6662.                 SetConnectionAttributes(hdbc,SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
  6663.             }
  6664.  
  6665.         }//end of the situation where SQLEndTran is supported
  6666.         else
  6667.         {
  6668.  
  6669.             switch(fHandleType[i])
  6670.             {
  6671.                 case SQL_HANDLE_ENV: 
  6672.                     rc= SQLEndTran(fHandleType[i],henv,SQL_COMMIT);
  6673.                     break;
  6674.                 case SQL_HANDLE_DBC: 
  6675.                     rc= SQLEndTran(fHandleType[i],hdbc,SQL_ROLLBACK);
  6676.                     break;
  6677.             }
  6678.  
  6679.             //check error msg
  6680.             if(!FindError(fHandleType[i],szIM001))
  6681.                 DISPLAYERROR(szSQLENDTRAN,TEXT("Did not return not Supported Message"));
  6682.  
  6683.             RETCHECK(SQL_ERROR, rc,szSQLENDTRAN);
  6684.  
  6685.             //free the hstmt handle
  6686.             FreeStmt(SQL_CLOSE);
  6687.  
  6688.         }//end of error msg checking
  6689.  
  6690.     }//end of the loop to check both henv and hdbc
  6691.  
  6692.     // Commit the transaction started in GetRowCnt inside ExecEndTran
  6693.     rc= SQLEndTran(SQL_HANDLE_ENV,henv,SQL_COMMIT);
  6694.     RETCHECK(SQL_SUCCESS, rc,szSQLENDTRAN);
  6695.  
  6696.     SetConnectionAttributes(hdbc,SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
  6697.  
  6698.     //free the hstmt handle
  6699.     FreeStmt(SQL_CLOSE);
  6700.  
  6701. } // TestEndTran()
  6702.  
  6703.  
  6704. //-----------------------------------------------------------------------
  6705. //    Function: TestBindParam
  6706. //
  6707. //        Test the SQLBindParam for SDK 3.0
  6708. //-----------------------------------------------------------------------
  6709. void  PASCAL TestBindParam(QTSTRUCT  *lpqt,FIELDINFO  *rgFields,UWORD cTypes,
  6710.                                         DSTRUCT  *lpd)
  6711. {
  6712.      RETCODE             rc;
  6713.     SQLINTEGER        cbValue = SQL_NTS;
  6714.     TCHAR                szDataItem[150];
  6715.  
  6716.     if(Supported(SQL_API_SQLBINDPARAM))
  6717.     {
  6718.         //test SQLBindParam by inserting one row, do not free the hstmt handle
  6719.         if (InsertOneRow(lpqt,rgFields,cTypes,lpd,(UWORD)(guwRowCount),FALSE))
  6720.             guwRowCount++; // We've inserted a row
  6721.     }
  6722.     else
  6723.     {
  6724.          //prepare the insert statement
  6725.         rc = SQLPrepare(hstmt, szInsertStmt, SQL_NTS);
  6726.         RETCHECK(SQL_SUCCESS, rc,szSQLPREPARE);
  6727.  
  6728.         //make data according to data type description in rgFields[0], cSeed is the seed
  6729.         qtMakeData(cTypes+1,0,&rgFields[0],szDataItem);
  6730.  
  6731.         //try to bind lpqt->szDataItem to the first column of the table
  6732.         rc = SQLBindParam(hstmt,1,SQL_C_TCHAR, rgFields[0].wSQLType, rgFields[0].precision,
  6733.                                 rgFields[0].scale,lpqt->szDataItem, &cbValue);
  6734.  
  6735.         //check error msg
  6736.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  6737.             DISPLAYERROR(szSQLBINDPARAM,TEXT("Did not return Not Supported Message"));
  6738.  
  6739.         RETCHECK(SQL_ERROR, rc,szSQLBINDPARAM);
  6740.     }
  6741.  
  6742.     //free the hstmt handle
  6743.     FreeStmt(SQL_CLOSE);
  6744.  
  6745. } // TestBindParam()
  6746.  
  6747.  
  6748.  
  6749.  
  6750.  
  6751.  
  6752. //-----------------------------------------------------------------------
  6753. //    Function: TestFetchScroll
  6754. //
  6755. //        Test the SQLFetchScroll for SDK 3.0
  6756. //-----------------------------------------------------------------------
  6757.  
  6758. void PASCAL TestFetchScroll(QTSTRUCT *lpqt)
  6759. {
  6760.     RETCODE    rc=SQL_SUCCESS;
  6761.     TCHAR        szSave[MAX_QUERY_SIZE];
  6762.     DWORD        dwLen=0;
  6763.     SDWORD    cbValue=0;
  6764.  
  6765.     /* check if SQLGetFunctions says your API is supported */
  6766.     if(!Supported( SQL_API_SQLFETCHSCROLL))
  6767.     {
  6768.         /* Call your 3.0 API here and verify that the correct state is returned */
  6769.         rc = SQLFetchScroll(hstmt,SQL_FETCH_FIRST, 0);
  6770.         if(!FindError(SQL_HANDLE_STMT,szIM001))
  6771.             DISPLAYERROR(szSQLFETCHSCROLL, szNotSupported);
  6772.         RETCHECK(SQL_ERROR, rc, szSQLFETCHSCROLL);
  6773.     }
  6774.     else
  6775.     {
  6776.         ResetHstmt(&hstmt);
  6777.  
  6778.         /* Valid Testing of SQLFetchScroll */
  6779.         SelectFromTable(lpqt);
  6780.  
  6781.         rc = SQLBindCol(hstmt, 1, SQL_C_TCHAR, lpqt->sz, MAX_BIND_ARRAY_ELEMENT,
  6782.             &cbValue);
  6783.         RETCHECK(SQL_SUCCESS, rc, szSQLBINDCOL);
  6784.  
  6785.         rc = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 3);
  6786.         RETCHECK(SQL_SUCCESS, rc, szSQLFETCHSCROLL);
  6787.         lstrcpy(szSave,lpqt->sz);
  6788.  
  6789.         rc = SQLFetchScroll(hstmt, SQL_FETCH_PRIOR, 1);
  6790.         RETCHECK(SQL_ERROR, rc, szSQLFETCHSCROLL);
  6791.  
  6792.         rc = SQLFetchScroll(hstmt, SQL_FETCH_FIRST, 0);
  6793.         RETCHECK(SQL_ERROR, rc, szSQLFETCHSCROLL);
  6794.  
  6795.         rc = SQLFetchScroll(hstmt, SQL_FETCH_LAST, 0);
  6796.         RETCHECK(SQL_ERROR, rc, szSQLFETCHSCROLL);
  6797.  
  6798.         rc = SQLFreeStmt(hstmt, SQL_CLOSE);
  6799.         RETCHECK(SQL_SUCCESS, rc, szSQLFREESTMT);
  6800.  
  6801.     }
  6802.  
  6803.     //free the hstmt handle
  6804.     FreeStmt(SQL_CLOSE);
  6805.  
  6806. } // TestFetchScroll()
  6807.  
  6808.  
  6809.  
  6810. /*-----------------------------------------------------------------------*/
  6811. /*      Function:               qtDisplayError                           */
  6812. /*-----------------------------------------------------------------------*/
  6813.  
  6814. void  PASCAL qtDisplayError(LPTSTR szFunction, LPTSTR buf, LPTSTR szFile, int iLine)
  6815. {
  6816.     TCHAR szTmp[MAX_STRING_SIZE];
  6817.  
  6818.     szWrite(TEXT(""), TRUE);
  6819.     szWrite(TEXT("\t\t\t"), FALSE);
  6820.     szWrite(szFunction, FALSE);
  6821.     szWrite(TEXT("  FAILED"), TRUE);
  6822.     szWrite(TEXT("\t\t\t"), FALSE);
  6823.     szWrite(buf, TRUE);
  6824.  
  6825.     wsprintf(szTmp,TEXT("\t\t\t%s: %d"), szFile, iLine);
  6826.     szWrite(szTmp, TRUE);
  6827.  
  6828.     szWrite(TEXT("\t\t\t  --------  "), TRUE);
  6829.  
  6830.     lpSI->failed++;
  6831.  
  6832.     return;
  6833. }
  6834.  
  6835.  
  6836. /*-----------------------------------------------------------------------*/
  6837. /*      Function:               qtMakeData                               */
  6838. /*-----------------------------------------------------------------------*/
  6839.  
  6840. LPTSTR  PASCAL qtMakeData(int row, int col,FIELDINFO  *rgField, LPTSTR buf)
  6841. {
  6842.     if(rgField->fAutoUpdate)
  6843.         return NULL;
  6844.  
  6845.     if(rgField->nullable && (row==col)) 
  6846.         {
  6847.         lstrcpy(buf,TEXT(""));
  6848.         return buf;
  6849.         }
  6850.  
  6851.     switch(rgField->wSQLType) {
  6852.         case SQL_CHAR:
  6853.         case SQL_VARCHAR:
  6854.         case SQL_LONGVARCHAR:
  6855.         case SQL_BINARY:
  6856.         case SQL_VARBINARY:
  6857.         case SQL_LONGVARBINARY:
  6858.             if(rgField->precision < 4)
  6859.                 wsprintf(buf,TEXT("%d"), 1);
  6860.             else
  6861.                 wsprintf(buf,TEXT("%d%d"), row, row);
  6862.             break;
  6863.         case SQL_DECIMAL:
  6864.         case SQL_NUMERIC:
  6865.         case SQL_REAL:
  6866.         case SQL_FLOAT:
  6867.         case SQL_DOUBLE:
  6868.             if(row == 2 && !rgField->fUnsigned) /* make the second row negative for variety */
  6869.                 wsprintf(buf,TEXT("-%d.%d"), row, row);
  6870.             else
  6871.                 wsprintf(buf,TEXT("%d.%d"), row, row);
  6872.             break;
  6873.  
  6874.         case SQL_BIT:
  6875.             if(row > 2)
  6876.                 wsprintf(buf,TEXT("%d"), 1);
  6877.             else
  6878.                 wsprintf(buf,TEXT("%d"), 0);
  6879.  
  6880.             break;
  6881.  
  6882.         case SQL_SMALLINT:
  6883.         case SQL_INTEGER:
  6884.         case SQL_TINYINT:
  6885.         case SQL_BIGINT:
  6886.             if(row == 2 && !rgField->fUnsigned) /* make the second row negative for variety */
  6887.                 wsprintf(buf,TEXT("-%d"), row);
  6888.             else
  6889.                 wsprintf(buf,TEXT("%d"), row);
  6890.             break;
  6891.  
  6892.         case SQL_TIME:
  6893.         case SQL_TYPE_TIME:
  6894.             wsprintf(buf,TEXT("{t '01:%02d:%02d'}"), row % 60, row % 60);
  6895.             break;
  6896.         case SQL_DATE:
  6897.         case SQL_TYPE_DATE:
  6898.             wsprintf(buf,TEXT("{d '1994-%02d-%02d'}"), (row % 12) + 1, (row % 30) + 1);
  6899.             break;
  6900.         case SQL_TIMESTAMP:
  6901.         case SQL_TYPE_TIMESTAMP:
  6902.             wsprintf(buf,TEXT("{ts '1994-%02d-%02d 01:%02d:%02d'}"), (row % 12) + 1, (row % 30) + 1, row % 60, row % 60);
  6903.             break;
  6904.     }
  6905.     return buf;
  6906. }
  6907.  
  6908.  
  6909.  
  6910.  
  6911. /*-----------------------------------------------------------------------*/
  6912. /*      Function:               TestNumResCols                           */
  6913. /*-----------------------------------------------------------------------*/
  6914.  
  6915. VOID PASCAL TestNumResCols(SDWORD cColsSelected,QTSTRUCT *lpqt)
  6916. {
  6917.     RETCODE    rc=SQL_SUCCESS;
  6918.     SWORD        wNum;
  6919.  
  6920.     SelectFromTable(lpqt);
  6921.  
  6922.     rc = SQLNumResultCols(hstmt, &wNum);
  6923.     RETCHECK(SQL_SUCCESS, rc,szSQLNUMRESULTCOLS);
  6924.  
  6925.     if(wNum != cColsSelected)
  6926.         DISPLAYERROR(szSQLNUMRESULTCOLS,TEXT("incorrect value returned"));
  6927.  
  6928.     FreeStmt(SQL_CLOSE);
  6929.  
  6930. } /* TestNumResCols() */
  6931.  
  6932.  
  6933.  
  6934. /*-----------------------------------------------------------------------*/
  6935. /*      Function:               TestNumResCols                           */
  6936. /*-----------------------------------------------------------------------*/
  6937.  
  6938. VOID PASCAL TestCursorName(QTSTRUCT *lpqt)
  6939. {
  6940.     RETCODE    rc=SQL_SUCCESS;
  6941.     TCHAR        szCursorName[MEDBUFF];
  6942.     SWORD        cb=0;
  6943.  
  6944.     SelectFromTable(lpqt);
  6945.  
  6946.     /* the cursor name should be created by the driver since one was    */
  6947.     /* not specified                                                                    */
  6948.  
  6949.     rc = SQLGetCursorName(hstmt, szCursorName, MAX_STRING_SIZE, &cb);
  6950.     RETCHECK(SQL_SUCCESS, rc,szSQLGETCURSORNAME);
  6951.  
  6952.     if(cb > MAX_STRING_SIZE)
  6953.     {
  6954.         DISPLAYERROR(szSQLGETCURSORNAME,TEXT("invalid cb"));
  6955.         cb = MAX_STRING_SIZE;
  6956.     }
  6957.  
  6958.     /* don't check the name itself, just make sure that    */
  6959.     /*    something was returned                                         */
  6960.     if(!*szCursorName) 
  6961.         DISPLAYERROR(szSQLGETCURSORNAME,TEXT("no name returned"));
  6962.  
  6963.     FreeStmt(SQL_CLOSE);
  6964.  
  6965. } /* TestCursorName() */
  6966.  
  6967.  
  6968. //-----------------------------------------------------------------------
  6969. //      Function:               GetDMVersion
  6970. //-----------------------------------------------------------------------
  6971.  
  6972. UWORD PASCAL GetDMVersion()
  6973. {
  6974.     RETCODE    rc=SQL_SUCCESS;
  6975.     TCHAR        szNum[MAX_NUM_BUFFER];
  6976.  
  6977.     rc = SQLGetInfo(hdbc, SQL_ODBC_VER, &szNum, MAX_NUM_BUFFER, NULL);
  6978.     RETCHECK(SQL_SUCCESS, rc,szSQLGETINFO);
  6979.     
  6980.     return((UWORD)_ttoi(_tcstok(szNum,TEXT("."))));
  6981.  
  6982. } /* GetDMVersion() */
  6983.  
  6984.  
  6985. //-----------------------------------------------------------------------
  6986. //      Function:               DisplayTestName
  6987. //-----------------------------------------------------------------------
  6988.  
  6989. VOID PASCAL DisplayTestName(UWORD i)
  6990. {
  6991.     szWrite(szBLANKLINE,TRUE);
  6992.     szWrite(szTAB,FALSE);
  6993.     szWrite(iTestNames[i-1], TRUE);
  6994.  
  6995. } /* DisplayTestName() */
  6996.  
  6997.  
  6998.  
  6999. /***************************  External Interfaces  *************************/
  7000. /*  These functions are called by Gator to envoke the tests.               */
  7001. /***************************************************************************/
  7002.  
  7003. BOOL CALLBACK AutoTestName(LPTSTR szName, UINT  * cbTestCases)
  7004. {
  7005.     static TCHAR szTestName[] = TEXT("Quick Test");
  7006.     
  7007.     lstrcpy(szName, szTestName);
  7008.     
  7009.     *cbTestCases = sizeof(iTestNames)/sizeof(LPTSTR);
  7010.  
  7011.     return TRUE;
  7012. }
  7013.  
  7014. //-----------------------------------------------------------------------
  7015. //      Function:               AutoTestDesc
  7016. //      Purpose:                        Provides gator with a list of tests which can be run.
  7017. //-----------------------------------------------------------------------
  7018. BOOL CALLBACK AutoTestDesc(UWORD iTest, LPTSTR szName, LPTSTR szDesc)
  7019. {
  7020.             
  7021.     UWORD len=0;
  7022.  
  7023.     if (iTest > (sizeof(iTestNames)/sizeof(LPTSTR)))
  7024.         return FALSE;
  7025.  
  7026.     if (szName)
  7027.          lstrcpy(szName,iTestNames[iTest-1]);
  7028.     
  7029.     if (szDesc)
  7030.         lstrcpy(szDesc,TEXT(" "));
  7031.     
  7032.     return TRUE;
  7033.  
  7034. }
  7035.  
  7036. //-----------------------------------------------------------------------
  7037. //      Function:               AutoTestFunc
  7038. //-----------------------------------------------------------------------
  7039.  
  7040. void CALLBACK AutoTestFunc(lpSERVERINFO pTestSource)
  7041. {
  7042.  
  7043.     RETCODE            rc;
  7044.     UWORD                cTypes;
  7045.     UDWORD            dwLen;
  7046.     UWORD                fIndex;
  7047.     SDWORD            cColsSelected;
  7048.     FIELDINFO        *rgFields = (FIELDINFO  *)AllocateMemory(sizeof(FIELDINFO) * MAX_TYPES_SUPPORTED);
  7049.     QTSTRUCT            *lpqt = (QTSTRUCT  *)AllocateMemory(sizeof (QTSTRUCT));
  7050.     DSTRUCT            *lpd = (DSTRUCT  *)AllocateMemory(sizeof (DSTRUCT) * MAX_TYPES_SUPPORTED);
  7051.     UWORD                uDMVer;
  7052.     SDWORD            cbValue=0;
  7053.     TCHAR                szAPI[MEDBUFF];
  7054.     UWORD                i;
  7055.     TCHAR        szState[100]=TEXT(""),
  7056.                 szErrMsg[XLARGEBUFF]=TEXT("");
  7057.  
  7058.  
  7059.     lpSI = pTestSource;
  7060.     lpSI->failed = 0;
  7061.     henv = NULL;
  7062.     hdbc = NULL;
  7063.     hstmt = NULL;
  7064.     hdesc = NULL;
  7065.  
  7066.     if(lpSI->szValidServer0)
  7067.     {
  7068.         if (Connect(lpSI,lpqt))
  7069.             goto ErrorRet;
  7070.     }
  7071.     else 
  7072.     {
  7073.         henv = lpSI->henv;
  7074.         hdbc = lpSI->hdbc;
  7075.         
  7076.         rc = SQLSetConnectOption(hdbc,SQL_ODBC_CURSORS,dwLen);
  7077.         lstrcpy(szAPI,szSQLSETCONNECTOPTION);
  7078.  
  7079.         if(RETCHECK(SQL_SUCCESS, rc,szAPI))
  7080.             lpSI->vCursorLib = dwLen;
  7081.     }
  7082.  
  7083.      uDMVer=GetDMVersion();
  7084.  
  7085.     fIndex=CheckConformanceLevel();
  7086.  
  7087.     fBindParameter=Supported(SQL_API_SQLBINDPARAMETER);
  7088.     fDiagRecSupported=Supported(SQL_API_SQLGETDIAGREC);
  7089.     fDiagFieldSupported=Supported(SQL_API_SQLGETDIAGFIELD);
  7090.  
  7091.  
  7092.     AllocHstmt();
  7093.  
  7094.     if (!(cTypes=GetTypeInfo(rgFields,lpqt)))
  7095.         goto ErrorRet;
  7096.  
  7097.     guwRowCount=cTypes+1;    // Extra row inserted with DAE.
  7098.  
  7099.     // cTypes=20;              //DEBUG
  7100.  
  7101.     /* build create statement */
  7102.     if (BuildCreateStmt(lpqt,rgFields,cTypes))
  7103.         goto ErrorRet;
  7104.  
  7105.     /* put together the insert statement, and set the parameters   */
  7106.     /* parameters are only set the first time through, after which */
  7107.     /* the contents of the pointers is changed                     */
  7108.     if (BuildInsertStmt(lpqt, rgFields,cTypes,lpd,&cColsSelected,fBindParameter))
  7109.         goto ErrorRet;
  7110.  
  7111.     CreateParamQuery(lpqt,rgFields,cTypes);
  7112.     
  7113.     for(i=1;i <= (sizeof(iTestNames)/sizeof(LPTSTR));i++)
  7114.     {
  7115.         lpqt->sz[0] = TEXT('\0');
  7116.  
  7117.         if(GETBIT(pTestSource->rglMask,i))
  7118.         {
  7119.             /* Display current Test */
  7120.             DisplayTestName(i);
  7121.  
  7122.             switch(i)
  7123.             {
  7124.                 case 1:
  7125.                     TestConnectionOptions();
  7126.                     break;
  7127.                 case 2:
  7128.                     TestStmtOptions();
  7129.                     break;
  7130.                 case 3:
  7131.                     TestCursorName(lpqt);
  7132.                     break;
  7133.                 case 4:
  7134.                     TestData(lpqt,rgFields,cTypes,lpd);
  7135.                     break;
  7136.                 case 5:
  7137.                     TestNumResCols(cColsSelected,lpqt);
  7138.                     break;
  7139.                 case 6:
  7140.                     TestMetaData(lpSI,lpqt,rgFields,cTypes);
  7141.                     break;
  7142.                 case 7:
  7143.                     TestSearchedQuery(lpqt,rgFields,cTypes,lpd,fBindParameter);
  7144.                     break;
  7145.                 case 8:
  7146.                     TestLargeQuery(lpqt,rgFields,cTypes,lpd);
  7147.                     break;
  7148.                 case 9:
  7149.                     TestSQLTables(lpqt);
  7150.                     break;
  7151.                 case 10:
  7152.                     TestSQLStatistics(lpqt,rgFields,cTypes,lpd,fIndex);
  7153.                     break;
  7154.                 case 11:
  7155.                     TestSQLSpecialCols(lpqt);
  7156.                     break;
  7157.                 case 12:
  7158.                     TestLikeQuery(lpqt,rgFields,cTypes,lpd);
  7159.                     break;
  7160.                 case 13:
  7161.                     TestSQLForeignKeys(lpqt);
  7162.                     break;
  7163.                 case 14:
  7164.                     TestSQLBrowseConnect(lpSI);
  7165.                     break;
  7166.                 case 15:
  7167.                     TestSQLDataSources();
  7168.                     break;
  7169.                 case 16:
  7170.                     TestSQLDrivers();
  7171.                     break;
  7172.                  case 17:
  7173.                     TestSQLMoreResults(lpqt);
  7174.                     break;
  7175.                  case 18:
  7176.                     TestSQLNativeSQL(lpqt);
  7177.                     break;
  7178.                 case 19:
  7179.                     TestSQLDescribeParam(lpqt);
  7180.                     break;
  7181.                 case 20:
  7182.                     TestSQLNumParams(lpqt);
  7183.                     break;
  7184.                 case 21:
  7185.                     TestSQLParamOptions(lpqt);
  7186.                     break;
  7187.                 case 22:
  7188.                     TestSQLPrimaryKeys(lpqt);
  7189.                     break;
  7190.                 case 23:
  7191.                     TestSQLProcedures();
  7192.                     break;
  7193.                 case 24:
  7194.                     TestSQLTablePrivileges();
  7195.                     break;
  7196.                 case 25:
  7197.                     TestSQLColumnPrivileges(lpqt);
  7198.                     break;
  7199.                 case 26:
  7200.                     TestSQLSetScrollOptions();
  7201.                     break;
  7202.                 case 27:
  7203.                     TestExtendedFetch(lpqt,rgFields,cTypes);
  7204.                     break;
  7205.                 case 28:
  7206.                     TestOJCap(lpqt);
  7207.                     break;
  7208.                 case 29:
  7209.                     TestSQLSetConnectAttr();
  7210.                     break;
  7211.                 case 30:
  7212.                     TestSQLSetStmtAttr();
  7213.                     break;
  7214.                 case 31:
  7215.                     TestThreading(lpSI,lpqt,rgFields);
  7216.                     break;
  7217.                 case 32:
  7218.                     TestGetDescField(lpqt);
  7219.                     break;
  7220.                 case 33:
  7221.                     TestSetDescField(lpqt);
  7222.                     break;
  7223.                 case 34:
  7224.                     TestGetDescRec(lpqt);
  7225.                     break;
  7226.                 case 35:
  7227.                     TestSetDescRec(lpqt);
  7228.                     break;
  7229.                 case 36:
  7230.                     TestCopyDesc(lpqt);
  7231.                     break;
  7232.                 case 37:
  7233.                     TestDescDefaults(lpqt);
  7234.                     break;
  7235.                 case 38:
  7236.                     TestUseDesc(lpqt, rgFields);
  7237.                     break;
  7238.                 case 39:
  7239.                     TestEnvAttr();
  7240.                     break;
  7241.                 case 40:
  7242.                     TestEndTran(lpqt,rgFields,cTypes,lpd);
  7243.                     break;
  7244.                 case 41:
  7245.                     TestBindParam(lpqt,rgFields,cTypes,lpd);
  7246.                     break;
  7247.                 case 42:
  7248.                     TestQuickRebind(lpqt,rgFields,cTypes,lpd);
  7249.                     break;
  7250.                 case 43:
  7251.                     TestFetchScroll(lpqt);
  7252.                     break;
  7253.                 case 44:
  7254.                     TestDiagRec();
  7255.                     break;
  7256.                 case 45:
  7257.                     TestDiagField();
  7258.                     break;
  7259.                 case 46:
  7260.                     TestMixedAnsiUnicode(lpqt);
  7261.                     break;
  7262.     
  7263.             } /* switch(i) */
  7264.  
  7265.         } /* if(GETBIT(pTestSource->rglMask,i)) */
  7266.     
  7267.     }
  7268.  
  7269.     //the end of test cases for ODBC SDK 3.0
  7270.  
  7271.     /* finished testing, clean up */
  7272.     CleanUp(lpd,lpqt,rgFields,lpqt->szTableName,FALSE,lpSI->szValidServer0);
  7273.  
  7274.     szWrite(szBLANKLINE,TRUE);
  7275.  
  7276.     lpSI->cErrors = lpSI->failed;
  7277.  
  7278.     return;
  7279.  
  7280. ErrorRet:
  7281.     /* a failure in an ODBC function that prevents completion of the    */
  7282.     /* test - for example, connect to the server                             */
  7283.  
  7284.     szWrite(TEXT("\t\t *** Unrecoverable Quick Test FAILURE ***"), TRUE);
  7285.  
  7286.     /* finished testing, clean up */
  7287.     CleanUp(lpd,lpqt,rgFields,lpqt->szTableName,FALSE,lpSI->szValidServer0);
  7288.  
  7289.     lpSI->cErrors = ABORT;
  7290.  
  7291.     return;
  7292. }
  7293.