home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Internet Business Development Kit / PRODUCT_CD.iso / sqlsvr / odbcsdk / samples / quiktest / quiktest.c < prev   
Encoding:
C/C++ Source or Header  |  1994-12-07  |  64.1 KB  |  2,066 lines

  1. /*
  2.   PROGRAM: quiktest.c
  3.         This code is furnished on an as-is basis as part of the ODBC SDK and is
  4.         intended for example purposes only.
  5.  
  6.   PURPOSE: This is a Quick Test of the basic functionality of an ODBC driver.
  7.         This 2.0 version of the Quick Test does not check the driver version
  8.         before calling 2.0 functions.
  9.  
  10.   FUNCTIONS:
  11.          QuickTest() - performs the quick test focusing on basic functionalities.
  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 "sql.h"
  21. #include "sqlext.h"
  22.  
  23. #define MAX_QUERY_SIZE 2048
  24. #define MAX_BIND_ELEMENTS 100
  25. #define MAX_BIND_ARRAY_ELEMENT MAX_QUERY_SIZE / MAX_BIND_ELEMENTS
  26. #define MAX_STRING_SIZE 100
  27. #define MAX_PARAM_SIZE 129
  28. #define MAX_DATA_SIZE 45
  29. #define MAX_COLUMN_LIST_SIZE 200
  30. #define MAX_COLUMN_NAME_SIZE 50
  31. #define MAX_INSERT_VALUES_SIZE 200
  32. #define MAX_TYPES_SUPPORTED 25
  33. #define MAX_TYPE_NAME 129
  34. #define MAX_FIELD 20
  35. #define MAX_PREFIX 129
  36. #define MAX_SUFFIX 129
  37. #define MAX_TABLE_NAME 30
  38. #define MAX_NUM_BUFFER 30
  39. #define MAX_ERROR_SIZE 200
  40. #define MAX_ROW_ITEM_LIMIT 4
  41. #define PREFIX_SIZE 3
  42. #define IGNORED 999
  43. #define TEST_CONNECT_OPTION 15
  44. #define TEST_STMT_OPTION 300
  45. #define SCALEDIFF 4
  46. #define ABORT -1
  47. #define TYPE_PORTION 4
  48.  
  49. /* used to store information from GetTypeInfo for table creation */
  50. typedef struct FieldInfo {
  51.         int iField;
  52.         char szType[MAX_TYPE_NAME];
  53.         char szFieldName[MAX_FIELD];
  54.         SWORD  wSQLType;
  55.         char szParams[MAX_PARAM_SIZE];
  56.         char szLength[MAX_FIELD];
  57.         char szPrefix[MAX_PREFIX];
  58.         char szSuffix[MAX_SUFFIX];
  59.         SDWORD precision;
  60.         SWORD scale;
  61.         SWORD nullable;
  62.         UDWORD length;
  63.         int   fAutoUpdate;
  64.         SWORD fSearchable;
  65.         SDWORD fUnsigned;
  66.         SWORD autoinc;
  67.         } FIELDINFO;
  68.  
  69. int FAR PASCAL ReturnCheck(RETCODE retExpected, RETCODE retReceived, LPSTR szFunction, LPSTR szFile, int iLine);
  70. void FAR PASCAL qtDisplayError(LPSTR szFunction, LPSTR buf, LPSTR szFile, int iLine);
  71. int FAR PASCAL FindError(LPSTR szFindState);
  72. int FAR PASCAL qtestristr(LPCSTR szString, LPCSTR szFind);
  73. LPSTR FAR PASCAL qtMakeData(int row, FIELDINFO FAR * rgField, LPSTR buf);
  74. VOID WINAPI szWrite(LPSTR szStr, BOOL fNewLine);
  75.  
  76. #define RETCHECK(exp, rec, buf) ReturnCheck(exp, rec, buf, __FILE__, __LINE__)
  77. #define DISPLAYERROR(func, string) qtDisplayError(func, string, __FILE__, __LINE__)
  78.  
  79. /* large buffers allocated as a global used for queries and other
  80. returned information */
  81. typedef struct  tagQtStruct {
  82.     char    buf[MAX_STRING_SIZE];
  83.     char    sz[MAX_QUERY_SIZE];
  84.     char  szParamQuery[MAX_QUERY_SIZE];
  85.     char    szParam[MAX_PARAM_SIZE];
  86.     char    szDataItem[MAX_DATA_SIZE];
  87.     char    szTableName[MAX_TABLE_NAME];
  88.     char    szColNames[MAX_COLUMN_LIST_SIZE];
  89.     char  szColName[MAX_COLUMN_NAME_SIZE];
  90.     char    szValues[MAX_INSERT_VALUES_SIZE];
  91. }       QTSTRUCT;
  92.  
  93. /* the storage used for data retreived using bind/fetch sequence 
  94. and data for BindParameter */
  95. /* only cb and one of the types will be used for each entry */
  96. typedef struct tagDataStruct {
  97.     SDWORD cb;
  98.     char data[MAX_STRING_SIZE];
  99.     SDWORD sdword;
  100.     SWORD sword;
  101.     SDOUBLE sdouble;
  102.     SFLOAT sfloat;
  103.     TIME_STRUCT time;
  104.     DATE_STRUCT date;
  105.     TIMESTAMP_STRUCT timestamp;
  106. } DSTRUCT;
  107.  
  108. lpSERVERINFO lpSI = NULL;
  109. static char vszFile[] = __FILE__;
  110.  
  111. /* these are globals so that the error functions can access them without
  112. needing to have them passed to every error check */
  113.     static HENV            henv;
  114.     static HDBC            hdbc;
  115.     static HSTMT           hstmt;
  116.  
  117.  
  118. //**************************************************************************
  119. //***************************  External Interfaces  ************************
  120. //*  These functions are called by Gator to envoke the tests.              *
  121. //**************************************************************************
  122.  
  123. BOOL CALLBACK AutoTestName(LPSTR szName, UINT FAR * cbTestCases)
  124. {
  125.     static char szTestName[] = "Quick Test";
  126.     lstrcpy(szName, szTestName);
  127.     *cbTestCases = 1;
  128.     return TRUE;
  129. }
  130.  
  131. //-----------------------------------------------------------------------
  132. //      Function:               AutoTestDesc
  133. //      Purpose:                        Provides gator with a list of tests which can be run.
  134. //-----------------------------------------------------------------------
  135. BOOL CALLBACK AutoTestDesc(UWORD iTest, LPSTR szName, LPSTR szDesc)
  136. {
  137.     switch(iTest)
  138.     {
  139.         case 1:
  140.             if(szName)
  141.                 lstrcpy(szName,"QuickTest");
  142.             if(szDesc)
  143.                 lstrcpy(szDesc,"QuickTest");
  144.             break;
  145.         default:
  146.             return FALSE;
  147.     }
  148.     return TRUE;
  149. }
  150.  
  151. //-----------------------------------------------------------------------
  152. //      Function:               AutoTestFunc
  153. //-----------------------------------------------------------------------
  154. void CALLBACK AutoTestFunc(lpSERVERINFO pTestSource)
  155. {
  156. //      extern int failed;
  157.  
  158.     RETCODE         returncode;
  159.     SWORD           wType;
  160.     SWORD           wNull;
  161.     SWORD           cb;
  162.     SWORD           wNum;
  163.     UWORD           w;
  164.     UWORD           i, j;
  165.     UWORD           ind;
  166.     UWORD           cTypes;
  167.     SDWORD          sdw;
  168.     UDWORD          dwLen;
  169.     UDWORD          udw;
  170.     BOOL            fFoundTable = 0;
  171.     PTR             ptr;
  172.     LPSTR           pch;
  173.     UWORD           cTableName;
  174.     BOOL            fColNames;
  175.     BOOL            fConnectOption;
  176.     UWORD           cFieldName = 0;
  177.     UWORD           fIndex = 0;
  178.     char            szNum[MAX_NUM_BUFFER];   /* used with atoi and itoa conversions */
  179.     int             same;
  180.     SDWORD          cColsSelected, cMaxTypeSize, cMaxRowSize = 0;
  181.     UWORD           cMaxConnections;
  182.     UWORD           fLevel2; 
  183.     UDWORD          fSupportedOpt;
  184.     UDWORD          fSupportedCon;
  185.     FIELDINFO FAR *rgFields = (FIELDINFO FAR *)AllocateMemory(sizeof(FIELDINFO) * MAX_TYPES_SUPPORTED);
  186.     QTSTRUCT FAR *lpqt = (QTSTRUCT FAR *)AllocateMemory(sizeof (QTSTRUCT));
  187.     DSTRUCT FAR *lpd = (DSTRUCT FAR *)AllocateMemory(sizeof (DSTRUCT) * MAX_TYPES_SUPPORTED);
  188.     UWORD        fBindParam;
  189.     UWORD        uDMVer;
  190.     BOOL        fVer201;
  191.     BOOL    fAutoInc = FALSE;
  192.  
  193.     lpSI = pTestSource;
  194.     lpSI->failed = 0;
  195.     henv = NULL;
  196.     hdbc = NULL;
  197.     hstmt = NULL;
  198.  
  199.     if(*pTestSource->szValidServer0) { /* The signal for test to use it's
  200.     own allocated handles, is if the a server name is passed in.  If it
  201.     is not, the test should use the hdbc passed in */
  202.         returncode = SQLAllocEnv(&henv);
  203.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLAllocEnv"))
  204.             goto ErrorRet;
  205.  
  206.         returncode = SQLAllocConnect(henv, &hdbc);
  207.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLAllocConnect"))
  208.             goto ErrorRet;
  209.  
  210.         returncode = SQLSetConnectOption(hdbc,SQL_ODBC_CURSORS,lpSI->vCursorLib);
  211.         RETCHECK(SQL_SUCCESS,returncode,"SQLSetConnectOption");
  212.  
  213.         /* create a DriverConnect string */
  214.         wsprintf(lpqt->sz, "dsn=%s;uid=%s;pwd=%s;",
  215.             (LPSTR)pTestSource->szValidServer0,
  216.             (LPSTR)pTestSource->szValidLogin0,
  217.             (LPSTR)pTestSource->szValidPassword0);
  218.  
  219.         /* since SQL_DRIVER_COMPLETE is used, it is possible that the
  220.             driver will bring up a dialog asking for more information. */
  221.         returncode = SQLDriverConnect(hdbc, pTestSource->hwnd, lpqt->sz,
  222.             SQL_NTS, lpqt->buf, MAX_STRING_SIZE, NULL, SQL_DRIVER_COMPLETE);
  223.  
  224.         if(returncode != SQL_SUCCESS && returncode !=
  225.             SQL_SUCCESS_WITH_INFO) {
  226.             /* in this situation, RETCHECK is used to display the error
  227.             message.  RETCHECK will display that SQL_SUCCESS was expected
  228.             although the error will only be displayed if neither SQL_SUCCESS
  229.             or SQL_SUCCESS_WITH_INFO was returned */
  230.             RETCHECK(SQL_SUCCESS, returncode, "SQLDriverConnect");
  231.             goto ErrorRet;
  232.         }
  233.  
  234.         returncode = SQLDisconnect(hdbc);
  235.         RETCHECK(SQL_SUCCESS, returncode, "SQLDisconnect");
  236.  
  237.         returncode = SQLConnect(hdbc, pTestSource->szValidServer0, SQL_NTS,
  238.             pTestSource->szValidLogin0, SQL_NTS,
  239.             pTestSource->szValidPassword0, SQL_NTS);
  240.  
  241.         if(returncode != SQL_SUCCESS && returncode !=
  242.             SQL_SUCCESS_WITH_INFO) {
  243.             RETCHECK(SQL_SUCCESS, returncode, "SQLConnect");
  244.             goto ErrorRet;
  245.         }
  246.     }
  247.     else {
  248.         henv = pTestSource->henv;
  249.         hdbc = pTestSource->hdbc;
  250.         
  251.         returncode = SQLGetConnectOption(hdbc,SQL_ODBC_CURSORS,&dwLen);
  252.         if(RETCHECK(SQL_SUCCESS, returncode, "SQLGetConnectOption"))
  253.             lpSI->vCursorLib = dwLen;
  254.     }
  255.  
  256.  
  257.  
  258.     returncode = SQLGetInfo(hdbc, SQL_ODBC_SQL_CONFORMANCE, &fIndex,
  259.         sizeof (fIndex), &cb);
  260.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetInfo");
  261.  
  262.     if(fIndex != 0 && fIndex != 1 && fIndex != 2) {
  263.         /* one of these two values should always be returned */
  264.         DISPLAYERROR("SQLGetInfo", "SQL_ODBC_API_CONFORMANCE - invalid value");
  265.     }
  266.     
  267.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLBINDPARAMETER, &fBindParam);
  268.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  269.     
  270.     returncode = SQLGetInfo(hdbc, SQL_ODBC_VER, &szNum, MAX_NUM_BUFFER, NULL);
  271.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetInfo");
  272.     uDMVer = (UWORD)atoi(strtok(szNum, "."));
  273.  
  274.     /* Set some options then get them and make sure they come back the
  275.         same. */
  276.  
  277.     returncode = SQLSetConnectOption(hdbc, SQL_ACCESS_MODE,
  278.         SQL_MODE_READ_WRITE);
  279.     if(returncode != SQL_SUCCESS)
  280.         if(!FindError("S1C00"))
  281.             RETCHECK(SQL_SUCCESS, returncode, "SQLSetConnectOption");
  282.  
  283.     returncode = SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, TRUE);
  284.     if(returncode != SQL_SUCCESS)
  285.         if(!FindError("S1C00"))
  286.             RETCHECK(SQL_SUCCESS, returncode, "SQLSetConnectOption");
  287.  
  288.     returncode = SQLSetConnectOption(hdbc, SQL_LOGIN_TIMEOUT, TEST_CONNECT_OPTION);
  289.     if(returncode != SQL_SUCCESS) {
  290.         if(!FindError("S1C00"))
  291.             RETCHECK(SQL_SUCCESS, returncode, "SQLSetConnectOption");
  292.         else
  293.             fConnectOption = FALSE;
  294.     } else
  295.         fConnectOption = TRUE;
  296.  
  297.     returncode = SQLGetConnectOption(hdbc, SQL_LOGIN_TIMEOUT, &sdw);
  298.     if(returncode != SQL_SUCCESS) {
  299.         if(!FindError("S1C00"))
  300.             RETCHECK(SQL_SUCCESS, returncode, "SQLGetConnectOption");
  301.     } else
  302.         if(sdw != TEST_CONNECT_OPTION && fConnectOption)
  303.             DISPLAYERROR("SQLGetConnectOption", "SQL_LOGIN_TIMEOUT returned incorrect value");
  304.  
  305.     returncode = SQLAllocStmt(hdbc, &hstmt);
  306.     RETCHECK(SQL_SUCCESS, returncode, "SQLAllocStmt");
  307.  
  308.     returncode = SQLGetStmtOption(hstmt, SQL_MAX_LENGTH, &udw);
  309.     if(returncode != SQL_SUCCESS)
  310.         if(!FindError("S1C00"))
  311.             RETCHECK(SQL_SUCCESS, returncode, "SQLGetConnectOption");
  312.  
  313.     returncode = SQLSetStmtOption(hstmt, SQL_MAX_LENGTH, TEST_STMT_OPTION);
  314.     if(returncode != SQL_SUCCESS)
  315.         if(!FindError("S1C00")) {
  316.             fConnectOption = FALSE;
  317.             RETCHECK(SQL_SUCCESS, returncode, "SQLGetConnectOption");
  318.         } else {
  319.             fConnectOption = TRUE;
  320.         }
  321.  
  322.     returncode = SQLGetStmtOption(hstmt, SQL_MAX_LENGTH, &dwLen);
  323.     if(returncode != SQL_SUCCESS) {
  324.         if(!FindError("S1C00"))
  325.             RETCHECK(SQL_SUCCESS, returncode, "SQLGetConnectOption");
  326.     } else
  327.         if(dwLen != TEST_STMT_OPTION && returncode == SQL_SUCCESS && fConnectOption)
  328.             DISPLAYERROR("SQLGetStmtOption", "incorrect SQL_MAX_LENGTH value returned");
  329.  
  330. /* Get the type information to use in a create statement for a table */
  331.  
  332.     returncode = SQLGetInfo(hdbc, SQL_MAX_COLUMN_NAME_LEN, &cFieldName,
  333.         sizeof cFieldName, NULL);
  334.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetInfo");
  335.  
  336.     returncode = SQLGetInfo(hdbc, SQL_MAX_ROW_SIZE, &cMaxRowSize,
  337.         sizeof cMaxRowSize, NULL);
  338.     /* don't check for SQL_SUCCES here, it's a 2.0 function.  If it's successful
  339.         That's great, if not then no maximum is assumed. */
  340.     
  341.     cMaxTypeSize = cMaxRowSize / MAX_TYPES_SUPPORTED;
  342.     
  343. /* TO DO: add checks in here for dos file types GetInfo SQL_QUALIFIER_NAME_SEPARATER */
  344.  
  345.     if(cFieldName > MAX_FIELD - 1)
  346.         cFieldName = MAX_FIELD - 1;
  347.     if(cFieldName < PREFIX_SIZE) {
  348.         DISPLAYERROR("SQLGetInfo", "MAX_COLUMN_NAME_LEN is too small for autotest to run");
  349.         goto ErrorRet;
  350.     }
  351.  
  352.     returncode = SQLGetTypeInfo(hstmt, SQL_ALL_TYPES);
  353.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetTypeInfo");
  354.  
  355.     for(i = 0; i < MAX_TYPES_SUPPORTED; i++) {
  356.     
  357.         returncode = SQLFetch(hstmt);
  358.         if(returncode != SQL_SUCCESS)
  359.             break;
  360.  
  361.         *rgFields[i].szType = *rgFields[i].szLength = *rgFields[i].szParams = '\0';
  362.  
  363.         /* get type name */
  364.         returncode = SQLGetData(hstmt, 1, SQL_C_CHAR,
  365.             (LPSTR)rgFields[i].szType, MAX_TYPE_NAME, &sdw);
  366.  
  367.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLGetData"))
  368.             goto ErrorRet;
  369.  
  370.         wsprintf(rgFields[i].szFieldName,"c%02u", i);
  371.         /* copy first portion of type name for easy reference */
  372.         strncat(rgFields[i].szFieldName, rgFields[i].szType, TYPE_PORTION);
  373.  
  374.  
  375.         /* change spaces in field name to '_' */
  376.         while((pch = (LPSTR)strchr(rgFields[i].szFieldName, ' ')) != NULL)
  377.             *pch = '_';
  378.  
  379.         /* get the SQLType */
  380.     returncode = SQLGetData(hstmt, 2, SQL_C_DEFAULT,
  381.             (SWORD FAR *)&rgFields[i].wSQLType, IGNORED,
  382.             &sdw);
  383.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLGetData"))
  384.             goto ErrorRet;
  385.  
  386.         /* Max length */
  387.         returncode = SQLGetData(hstmt, 3, SQL_C_CHAR,
  388.             (LPSTR)rgFields[i].szLength, MAX_FIELD, &sdw);
  389.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLGetData"))
  390.             goto ErrorRet;
  391.  
  392.         /* limit the row size for those drivers that don't support a long
  393.             enough row length for all the fields to be at the max length */
  394.         switch(rgFields[i].wSQLType) {
  395.             case SQL_CHAR:
  396.             case SQL_VARCHAR:
  397.             case SQL_VARBINARY:
  398.             case SQL_BINARY:
  399.             case SQL_LONGVARCHAR:
  400.             case SQL_LONGVARBINARY:
  401.  
  402.                 if(cMaxTypeSize) {
  403.                     if(atol (rgFields[i].szLength) > cMaxTypeSize)
  404.                         _ltoa(cMaxTypeSize, rgFields[i].szLength, 10);
  405.                 }
  406.         }
  407.  
  408.         /* prefix */
  409.         returncode = SQLGetData(hstmt, 4, SQL_C_CHAR,
  410.             (LPSTR)rgFields[i].szPrefix, MAX_PREFIX, &sdw);
  411.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLGetData"))
  412.             goto ErrorRet;
  413.  
  414.         /* suffix */
  415.         returncode = SQLGetData(hstmt, 5, SQL_C_CHAR,
  416.             (LPSTR)rgFields[i].szSuffix, MAX_SUFFIX, &sdw);
  417.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLGetData"))
  418.             goto ErrorRet;
  419.  
  420.         /* create params */
  421.         returncode = SQLGetData(hstmt, 6, SQL_C_CHAR,
  422.             (LPSTR)rgFields[i].szParams, MAX_PARAM_SIZE, &sdw);
  423.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLGetData"))
  424.             goto ErrorRet;
  425.  
  426.         /* nullable */
  427.         returncode = SQLGetData(hstmt, 7, SQL_C_SHORT, &rgFields[i].nullable, IGNORED,
  428.             &sdw);
  429.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLGetData"))
  430.             goto ErrorRet;
  431.  
  432.         /* searchable */
  433.         returncode = SQLGetData(hstmt, 9, SQL_C_SHORT, &rgFields[i].fSearchable, IGNORED,
  434.             &sdw);
  435.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLGetData"))
  436.             goto ErrorRet;
  437.  
  438.         /* autoincrement */
  439.         returncode = SQLGetData(hstmt, 12, SQL_C_SHORT, &rgFields[i].autoinc, IGNORED,
  440.             &sdw);
  441.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLGetData"))
  442.             goto ErrorRet;
  443.  
  444. /* If a line below is compiled in, that type will not be used in creating
  445.  the table.  (useful for when one specific type is causing problems in
  446.  a particular test, this way the test can be run for all other types)
  447. */
  448.             if(!lstrcmp(rgFields[i].szType, "LONG RAW")) {
  449.                 i--;
  450.                 continue;
  451.             }
  452.             if(!lstrcmp(rgFields[i].szType, "LONG VARCHAR")) {
  453.                 i--;
  454.                 continue;
  455.             }
  456.             if(!lstrcmp(rgFields[i].szType, "LONG VARCHAR FOR BIT DATA")) {
  457.                 i--;
  458.                 continue;
  459.             }
  460.             
  461.         /* The following code only allows the first autoincrement column to
  462.             be placed in the table.  Many DBMS's do not allow more than one per table. */
  463.         if(rgFields[i].autoinc == TRUE){
  464.             if(fAutoInc){
  465.                 i--;
  466.                 continue;
  467.                 }
  468.             else
  469.                 fAutoInc = TRUE;
  470.             }
  471.     }
  472.     cTypes = i;
  473.  
  474.     /* if the type name contains spaces, replace them with _ because
  475.         most servers don't allow spaces in field names */
  476.  
  477.     RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  478.  
  479.     returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  480.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  481.  
  482.     returncode = SQLGetInfo(hdbc, SQL_MAX_TABLE_NAME_LEN, &cTableName,
  483.         sizeof (int), NULL);
  484.     if(returncode != SQL_SUCCESS && returncode != SQL_SUCCESS_WITH_INFO)
  485.         RETCHECK(SQL_SUCCESS, returncode, "SQLGetInfo");
  486.  
  487.     returncode = SQLGetInfo(hdbc, SQL_QUALIFIER_NAME_SEPARATOR, lpqt->buf,
  488.         MAX_STRING_SIZE, NULL);
  489.     if(returncode != SQL_SUCCESS && returncode != SQL_SUCCESS_WITH_INFO)
  490.         RETCHECK(SQL_SUCCESS, returncode, "SQLGetInfo");
  491.  
  492.     if(0 == lstrcmp("\\", lpqt->buf))
  493.         cTableName -= 4;
  494.     _snprintf(lpqt->szTableName, min(cTableName, MAX_TABLE_NAME-1),
  495.                 "q%ld", hstmt);
  496.  
  497.     /* build create statement */
  498.     /* the column names will be ctypname (where typename is the
  499.         type name returned by the source in SQLGetTypeInfo) */
  500.  
  501.     *lpqt->sz = '\0';
  502.     lstrcpy(lpqt->sz, "Create Table ");
  503.     lstrcat(lpqt->sz, lpqt->szTableName);
  504.     lstrcat(lpqt->sz, " (");
  505.     for(i = 0; i < cTypes; i++) {
  506.             char szParamType[50];
  507.             char szNotNull[10];
  508.             *lpqt->szParam = '\0';
  509.  
  510.         /* if SQLGetTypeInfo returned params they need to be used in
  511.             the create statement */
  512.         
  513.         if(rgFields[i].szParams == NULL || lstrlen(rgFields[i].szParams) == 0)
  514.             *lpqt->szParam = '\0';
  515.         else if(strchr(rgFields[i].szParams, ',') == NULL)
  516.             wsprintf(lpqt->szParam, "(%s)", rgFields[i].szLength);
  517.         else {
  518.             lstrcpy(szNum, rgFields[i].szLength);
  519.             wsprintf(lpqt->szParam, "(%s, %d)", rgFields[i].szLength,
  520.                 atoi(szNum) - SCALEDIFF);
  521.         }
  522.  
  523.         lstrcpy(szParamType, rgFields[i].szType);
  524.         if(pch = strchr((LPSTR)szParamType, '(')) {
  525.             *pch = '\0';
  526.             lstrcat(szParamType, lpqt->szParam);
  527.             lstrcat(szParamType, (LPSTR)strchr(rgFields[i].szType, ')') + 1);
  528.         } else {
  529.             lstrcat(szParamType, lpqt->szParam);
  530.         }
  531.         /* If the field is not nullable, we need to create the table that way */
  532.         returncode = SQLGetInfo(hdbc, SQL_NON_NULLABLE_COLUMNS, &wNum,
  533.             sizeof (SWORD), NULL);
  534.         if(returncode != SQL_SUCCESS && returncode != SQL_SUCCESS_WITH_INFO)
  535.             RETCHECK(SQL_SUCCESS, returncode, "SQLGetInfo");
  536.         
  537.         if((rgFields[i].nullable == SQL_NO_NULLS) && (wNum != SQL_NNC_NULL))
  538.             lstrcpy(szNotNull, "NOT NULL");
  539.         else
  540.             szNotNull[0] = '\0';
  541.         
  542.         wsprintf(&lpqt->sz[lstrlen(lpqt->sz)], " %s %s %s, ",
  543.             (LPSTR)rgFields[i].szFieldName, (LPSTR)szParamType, (LPSTR)szNotNull);
  544.     }
  545.  
  546.     /* remove the last comma and space */
  547.     lpqt->sz[lstrlen(lpqt->sz) - 2] = '\0';
  548.     lstrcat(lpqt->sz, ")");
  549.  
  550.     returncode = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  551.     if(returncode != SQL_SUCCESS && returncode != SQL_SUCCESS_WITH_INFO)
  552.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLExecDirect"))
  553.             goto ErrorRet;
  554.  
  555.     /* now that table was created, call SQLColumns.  Both as
  556.         a test and to get necessary information to insert data */
  557.  
  558.     returncode = SQLColumns(hstmt, NULL, SQL_NTS, NULL, SQL_NTS,
  559.         lpqt->szTableName, SQL_NTS, NULL, SQL_NTS);
  560.     RETCHECK(SQL_SUCCESS, returncode, "SQLColumns");
  561.  
  562.     for(i = 0; i < cTypes; i++) {
  563.         returncode = SQLFetch(hstmt);
  564.         RETCHECK(SQL_SUCCESS, returncode, "SQLFetch");
  565.  
  566.         /* precision */
  567.         returncode = SQLGetData(hstmt, 7, SQL_C_LONG, &rgFields[i].precision, IGNORED,
  568.             &sdw);
  569.         RETCHECK(SQL_SUCCESS, returncode, "SQLGetData");
  570.  
  571.         /* length */
  572.         if((rgFields[i].precision == 0) || (sdw == SQL_NO_TOTAL)){
  573.             returncode = SQLGetData(hstmt, 8, SQL_C_LONG, &rgFields[i].precision, IGNORED,
  574.                 &sdw);
  575.             RETCHECK(SQL_SUCCESS, returncode, "SQLGetData");
  576.             if(sdw == SQL_NO_TOTAL)        /* precision & length were undetermined */
  577.                 rgFields[i].precision = 1000;    /* so set it to an arbitary value */
  578.         }
  579.  
  580.         /* numeric scale */
  581.         returncode = SQLGetData(hstmt, 9, SQL_C_SHORT, &rgFields[i].scale, IGNORED,
  582.             &sdw);
  583.         RETCHECK(SQL_SUCCESS, returncode, "SQLGetData");
  584.         if(sdw == SQL_NO_TOTAL)
  585.             rgFields[i].scale = 0;
  586.     }
  587.  
  588.     returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  589.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  590.  
  591.     /* look for columns the test should not try to update by running
  592.         a select * query and calling ColAttributes on the result fields */
  593.     /* select * does not return the fields in a defined order, so field order
  594.         must be specified */
  595.  
  596.     lstrcpy(lpqt->sz, "select ");
  597.     for(i = 0; i < cTypes; i ++) {
  598.         if(i)
  599.             lstrcat(lpqt->sz, ",");
  600.         lstrcat(lpqt->sz, rgFields[i].szFieldName);
  601.     }
  602.  
  603.     lstrcat(lpqt->sz, " from ");
  604.     lstrcat(lpqt->sz, lpqt->szTableName);
  605.  
  606.     returncode = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  607.     RETCHECK(SQL_SUCCESS, returncode, "SQLExecDirect");
  608.  
  609.     for(i = 1; i <= cTypes; i++) {
  610.  
  611.         returncode = SQLColAttributes(hstmt, i, SQL_COLUMN_UPDATABLE, NULL,
  612.             0, NULL, &sdw);
  613.         RETCHECK(SQL_SUCCESS, returncode, "SQLColAttributes");
  614.  
  615.         rgFields[i - 1].fAutoUpdate = sdw == SQL_ATTR_READONLY;
  616.  
  617.         returncode = SQLColAttributes(hstmt, i, SQL_COLUMN_UNSIGNED, NULL,
  618.             0, NULL, &sdw);
  619.         RETCHECK(SQL_SUCCESS, returncode, "SQLColAttributes");
  620.  
  621.         rgFields[i - 1].fUnsigned = sdw;
  622.     }
  623.  
  624.     returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  625.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  626.  
  627.     /* put together the insert statement, and set the parameters */
  628.     /* parameters are only set the first time through, after which
  629.     the contents of the pointers is changed */
  630.  
  631.     *lpqt->szColNames = '\0';
  632.     *lpqt->szValues = '\0';
  633.     fColNames = TRUE;
  634.  
  635.     for(i = 0; i < cTypes; i++) {
  636.         for(ind = 0, w = 0; ind < cTypes; ind++) {
  637.             pch = qtMakeData(i, &rgFields[ind], lpqt->szDataItem);
  638.  
  639.             if(!pch) /* current type is READ_ONLY) */
  640.                 continue;
  641.  
  642.             /* for every nullable type, that field will be set to
  643.             null when the row number corresponds with the field
  644.             number */
  645.  
  646.             if(*pch) {
  647.                 lstrcpy(lpd[w].data, pch);
  648.                 lpd[w].cb = SQL_NTS;
  649.             }
  650.             else {
  651.                 lstrcpy(lpd[w].data, "");
  652.                 lpd[w].cb = SQL_NULL_DATA;
  653.             }
  654.  
  655.             if(fColNames) { /* the first time throught, the insert
  656.                 statement itself is created */
  657.                 lstrcat(lpqt->szColNames, rgFields[ind].szFieldName);
  658.                 lstrcat(lpqt->szColNames, ", ");
  659.                 lstrcat(lpqt->szValues, " ?, ");
  660.  
  661.                 /* and parameters are set */
  662.                 /* set all the parameters using pointers to buffers in
  663.                 the param struct. */
  664.                 if(!fBindParam){
  665.                     returncode = SQLSetParam(hstmt, (UWORD)(w+1),
  666.                         SQL_C_CHAR, rgFields[ind].wSQLType,
  667.                         rgFields[ind].precision, rgFields[ind].scale,
  668.                         &lpd[w].data,
  669.                         &lpd[w].cb);
  670.                     RETCHECK(SQL_SUCCESS, returncode, "SQLSetParam");
  671.                     }
  672.                 else{
  673.                     returncode = SQLBindParameter(hstmt, (UWORD)(w+1),
  674.                         SQL_PARAM_INPUT,
  675.                         SQL_C_CHAR, rgFields[ind].wSQLType,
  676.                         rgFields[ind].precision, rgFields[ind].scale,
  677.                         &lpd[w].data, 100,
  678.                         &lpd[w].cb);
  679.                     RETCHECK(SQL_SUCCESS, returncode, "SQLBindParameter");
  680.                     }
  681.             }
  682.             w++;
  683.         }
  684.  
  685.         if(fColNames) { /* the first time through, the insert
  686.             statement needs to be SQLPrepare'd */
  687.             /* remove the ", " at the end of the string */
  688.             lpqt->szColNames[lstrlen(lpqt->szColNames) - 2] = '\0';
  689.             lpqt->szValues[lstrlen(lpqt->szValues) - 2] = '\0';
  690.  
  691.             wsprintf(lpqt->sz, "insert into %s (%s) VALUES(%s)",
  692.                 lpqt->szTableName, lpqt->szColNames, lpqt->szValues);
  693.  
  694.             returncode = SQLPrepare(hstmt, lpqt->sz, SQL_NTS);
  695.             if(!RETCHECK(SQL_SUCCESS, returncode, "SQLPrepare"))
  696.                 goto ErrorRet;
  697.  
  698.             fColNames = FALSE; /* no more first times through */
  699.         }
  700.  
  701.         returncode = SQLExecute(hstmt); /* insert a row */
  702.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLExecute"))
  703.             goto ErrorRet;
  704.  
  705.         returncode = SQLRowCount(hstmt, &sdw);
  706.         RETCHECK(SQL_SUCCESS, returncode, "SQLRowCount");
  707.  
  708.         if(sdw != 1) /* the execute inserted 1 row */
  709.             DISPLAYERROR("SQLRowCount", "Insert single row");
  710.  
  711.         /* FreeStmt SQL_CLOSE */
  712.         returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  713.         RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  714.     }
  715.  
  716.     /* for the last row use SQLParamData and SQLPutData */
  717.  
  718.     sdw = SQL_DATA_AT_EXEC;
  719.  
  720.     for(ind = 0, w = 0; ind < cTypes; ind++) { /* set all the params */
  721.         if(rgFields[ind].fAutoUpdate)
  722.             continue;
  723.  
  724.         w++;
  725.         if(!fBindParam){
  726.             returncode = SQLSetParam(hstmt, w,
  727.                 SQL_C_CHAR, rgFields[ind].wSQLType,
  728.                 rgFields[ind].precision, rgFields[ind].scale,
  729.                 (LPSTR)(UDWORD)ind, &sdw);
  730.             RETCHECK(SQL_SUCCESS, returncode, "SQLSetParam");
  731.             }
  732.         else{
  733.             returncode = SQLBindParameter(hstmt, w, SQL_PARAM_INPUT,
  734.                 SQL_C_CHAR, rgFields[ind].wSQLType,
  735.                 rgFields[ind].precision, rgFields[ind].scale,
  736.                 (LPSTR)(UDWORD)ind, 0, &sdw);
  737.             RETCHECK(SQL_SUCCESS, returncode, "SQLBindParameter");
  738.             }
  739.     }
  740.  
  741.     cColsSelected = w;
  742.  
  743.     returncode = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  744.     RETCHECK(SQL_NEED_DATA, returncode, "SQLExecDirect");
  745.  
  746.     for(ind = 0; ind <= cTypes; ind++) {
  747.         returncode = SQLParamData(hstmt, &ptr);
  748.         if(returncode != SQL_NEED_DATA)
  749.             break;
  750.  
  751.         pch = qtMakeData(cTypes, &rgFields[(unsigned long)ptr],
  752.             lpqt->szDataItem);
  753.  
  754.         if(*pch) {
  755.             returncode = SQLPutData(hstmt, pch, SQL_NTS);
  756.             RETCHECK(SQL_SUCCESS, returncode, "SQLPutData");
  757.         } else {
  758.             returncode = SQLPutData(hstmt, (LPSTR)IGNORED, SQL_NULL_DATA);
  759.             RETCHECK(SQL_SUCCESS, returncode, "SQLPutData");
  760.         }
  761.     }
  762.  
  763.     RETCHECK(SQL_SUCCESS, returncode, "SQLParamData");
  764.  
  765.     returncode = SQLRowCount(hstmt, &sdw);
  766.     RETCHECK(SQL_SUCCESS, returncode, "SQLRowCount");
  767.  
  768.     if(sdw != 1)
  769.         DISPLAYERROR("SQLRowCount", "Insert single row");
  770.  
  771.     returncode = SQLFreeStmt(hstmt, SQL_RESET_PARAMS);
  772.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  773.  
  774.     /* now that the table is created and has data, make sure it
  775.         all comes back correctly */
  776.  
  777.     wsprintf(lpqt->sz, "select %s from %s", lpqt->szColNames, lpqt->szTableName);
  778.  
  779.     returncode = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  780.     RETCHECK(SQL_SUCCESS, returncode, "SQLExecDirect");
  781.  
  782.     lpqt->sz[0] = '\0';
  783.  
  784.     /* the cursor name should be created by the driver since one was
  785.         not specified */
  786.  
  787.     returncode = SQLGetCursorName(hstmt, lpqt->sz, MAX_STRING_SIZE, &cb);
  788.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetCursorName");
  789.  
  790.     if(cb > MAX_STRING_SIZE) {
  791.         DISPLAYERROR("SQLGetCursorName", "invalid cb");
  792.         cb = MAX_STRING_SIZE;
  793.     }
  794.  
  795.     if(!*lpqt->sz) { /* don't check the name itself, just make sure that 
  796.         something was returned */
  797.         DISPLAYERROR("SQLGetCursorName", "no name returned");
  798.     }
  799.  
  800.     returncode = SQLNumResultCols(hstmt, &wNum);
  801.     RETCHECK(SQL_SUCCESS, returncode, "SQLNumResultCols");
  802.  
  803.     if(wNum != cColsSelected) {
  804.         DISPLAYERROR("SQLNumResultCols", "incorrect value returned");
  805.     }
  806.  
  807.     for(i = 0, w = 0; i < cTypes; i++) {
  808.         dwLen = 0;
  809.         wNum = 0;
  810.         wNull = 0;
  811.  
  812.         /* information returned by SQLDescribeCol should match info
  813.             used to create table */
  814.  
  815.         if(!qtMakeData(1, &rgFields[i],
  816.             lpqt->szDataItem))
  817.             continue;
  818.  
  819.         w++;
  820.         returncode = SQLDescribeCol(hstmt, w, lpqt->buf,
  821.             MAX_STRING_SIZE, NULL, &wType, &dwLen, &wNum, &wNull);
  822.         RETCHECK(SQL_SUCCESS, returncode, "SQLDescribeCol");
  823.  
  824.         /* verify that column name returned is column name created */
  825.  
  826.         if(0 != lstrcmpi(rgFields[i].szFieldName, lpqt->buf)) {
  827.             DISPLAYERROR("SQLDescribeCol", "incorrect column name");
  828.         }
  829.  
  830.         if(wType != rgFields[i].wSQLType) {
  831.             DISPLAYERROR("SQLDescribeCol", "incorrect SQLType");
  832.         }
  833.  
  834.         if(dwLen != (UDWORD)rgFields[i].precision) {
  835.             DISPLAYERROR("SQLDescribeCol", "incorrect precision");
  836.         }
  837.  
  838.         if(wNum != rgFields[i].scale) {
  839.             DISPLAYERROR("SQLDescribeCol", "incorrect scale");
  840.         }
  841.  
  842.         if(wNull != rgFields[i].nullable && wNull != SQL_NULLABLE_UNKNOWN &&
  843.             rgFields[i].nullable != SQL_NULLABLE_UNKNOWN) {
  844.             DISPLAYERROR("SQLDescribeCol", "incorrect nullable");
  845.         }
  846.     }
  847.  
  848. /* bind all fields to a variable of the correct type for retreiving data */
  849.  
  850.     for(i = 0, w = 0; i < cTypes; i++) {
  851.  
  852.         if(!qtMakeData(1, &rgFields[i],
  853.             lpqt->szDataItem))
  854.             continue;
  855.  
  856.         w++;
  857.  
  858.         switch(rgFields[i].wSQLType) {
  859.             case SQL_INTEGER:
  860.         returncode = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  861.                     &lpd[i].sdword, IGNORED, &lpd[i].cb);
  862.                 break;
  863.             case SQL_SMALLINT:
  864.         returncode = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  865.                     &lpd[i].sword, IGNORED, &lpd[i].cb);
  866.                 break;
  867.             case SQL_FLOAT:
  868.             case SQL_DOUBLE:
  869.         returncode = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  870.                     &lpd[i].sdouble, IGNORED, &lpd[i].cb);
  871.                 break;
  872.             case SQL_REAL:
  873.         returncode = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  874.                     &lpd[i].sfloat, IGNORED, &lpd[i].cb);
  875.                 break;
  876.             case SQL_DATE:
  877.         returncode = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  878.                     &lpd[i].date, IGNORED, &lpd[i].cb);
  879.                 break;
  880.             case SQL_TIME:
  881.         returncode = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  882.                     &lpd[i].time, IGNORED, &lpd[i].cb);
  883.                 break;
  884.             case SQL_TIMESTAMP:
  885.         returncode = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  886.                     &lpd[i].timestamp, IGNORED, &lpd[i].cb);
  887.                 break;
  888.             case SQL_CHAR:
  889.             case SQL_VARCHAR:
  890.             case SQL_NUMERIC:
  891.             case SQL_DECIMAL:
  892.             default:
  893.         returncode = SQLBindCol(hstmt, w, SQL_C_DEFAULT,
  894.                     lpd[i].data, MAX_STRING_SIZE, &lpd[i].cb);
  895.                 break;
  896.         }
  897.  
  898.         if(!RETCHECK(SQL_SUCCESS, returncode, "SQLBindCol"))
  899.             goto ErrorRet;
  900.     }
  901.  
  902.     for(ind = 0;; ind++) {
  903.  
  904.         /* Get the data back */
  905.         returncode = SQLFetch(hstmt);
  906.         if(returncode != SQL_SUCCESS && returncode != SQL_SUCCESS_WITH_INFO)
  907.             break;
  908.  
  909.         for(i = 0; i < cTypes; i++) { /* make sure it's original data placed
  910.             in that field/row location */
  911.             pch = qtMakeData(ind, &rgFields[i], lpqt->szDataItem);
  912.  
  913.             if(!pch)
  914.                 continue;
  915.  
  916.             if(!*pch) {
  917.                 if(lpd[i].cb != SQL_NULL_DATA)
  918.                     DISPLAYERROR("returned data", "should have been NULL");
  919.                 continue;
  920.             }
  921.             switch(rgFields[i].wSQLType) { /* check the outlen and data
  922.                 returned for each type. */
  923.                 case SQL_INTEGER:
  924.                     if(lpd[i].cb != sizeof(SDWORD))
  925.                         DISPLAYERROR("returned data", "incorrect outlen");
  926.  
  927.                     lstrcpy(szNum, pch);
  928.                     same = atol(szNum) == lpd[i].sdword;
  929.                     break;
  930.                 case SQL_SMALLINT:
  931.                     if(lpd[i].cb != sizeof(SWORD))
  932.                         DISPLAYERROR("returned data", "incorrect outlen");
  933.  
  934.                     lstrcpy(szNum, pch);
  935.                     same = atoi(szNum) == lpd[i].sword;
  936.                     break;
  937.  
  938.                 case SQL_FLOAT:
  939.                 case SQL_DOUBLE:
  940.                     if(lpd[i].cb != sizeof(SDOUBLE))
  941.                         DISPLAYERROR("returned data", "incorrect outlen");
  942.  
  943.                     lstrcpy(szNum, pch);
  944.                     same = atof(szNum) - lpd[i].sdouble < 0.001 &&
  945.                         atof(szNum) - lpd[i].sdouble > -0.001;
  946.                     break;
  947.  
  948.                 case SQL_REAL:
  949.                     if(lpd[i].cb != sizeof(SFLOAT))
  950.                         DISPLAYERROR("returned data", "incorrect outlen");
  951.  
  952.                     lstrcpy(szNum, pch);
  953.                     same = atof(szNum) - lpd[i].sfloat < 0.001 &&
  954.                         atof(szNum) - lpd[i].sfloat > -0.001;
  955.                     break;
  956.  
  957.                 case SQL_TINYINT:
  958.                     if(lpd[i].cb != sizeof(char))
  959.                         DISPLAYERROR("returned data", "incorrect outlen");
  960.  
  961.                     lstrcpy(szNum, pch);
  962.                     same = (char)atoi(szNum) == (char)lpd[i].data[0];
  963.                     break;
  964.  
  965.                 case SQL_DECIMAL:
  966.                 case SQL_NUMERIC:
  967.                     if(lpd[i].cb > MAX_STRING_SIZE)
  968.                         DISPLAYERROR("returned data", "incorrect outlen");
  969.  
  970.                     if(lpd[i].cb > lstrlen(lpd[i].data))
  971.                         DISPLAYERROR("returned data", "incorrect outlen");
  972.  
  973.                     {
  974.                     char szNum2[MAX_NUM_BUFFER];
  975.  
  976.                     lstrcpy(szNum, pch);
  977.                     lstrcpy(szNum2, pch);
  978.                     same = atof(szNum) - atof(szNum2) < 0.001 &&
  979.                         atof(szNum) - atof(szNum2) > -0.001;
  980.                     }
  981.  
  982.                     break;
  983.  
  984.  
  985.                 case SQL_VARCHAR:
  986.                 case SQL_LONGVARCHAR:
  987.                     if(lpd[i].cb > MAX_STRING_SIZE)
  988.                         DISPLAYERROR("returned data", "incorrect outlen");
  989.  
  990.                     if(lpd[i].cb > lstrlen(lpd[i].data))
  991.                         DISPLAYERROR("returned data", "incorrect outlen");
  992.  
  993.                     same = !!strstr(lpd[i].data, pch);
  994.  
  995.                     break;
  996.  
  997.                 case SQL_VARBINARY:
  998.                 case SQL_LONGVARBINARY:
  999.                     if(lpd[i].cb > MAX_STRING_SIZE)
  1000.                         DISPLAYERROR("returned data", "incorrect outlen");
  1001.  
  1002.                     if(lpd[i].cb  * 2 != lstrlen(pch))
  1003.                         DISPLAYERROR("returned data", "incorrect outlen");
  1004.  
  1005.                     same = TRUE; /* not checking returned data for binary */
  1006.  
  1007.                     break;
  1008.  
  1009.                 case SQL_CHAR:
  1010.                     if(lpd[i].cb > MAX_STRING_SIZE && returncode == SQL_SUCCESS)
  1011.                         DISPLAYERROR("returned data", "incorrect return code for outlen");
  1012.  
  1013.                     if(lpd[i].cb != rgFields[i].precision && returncode == SQL_SUCCESS)
  1014.                         DISPLAYERROR("returned data", "incorrect outlen");
  1015.  
  1016.                     same = !strncmp(lpd[i].data, pch, lstrlen(pch));
  1017.  
  1018.                     break;
  1019.                 case SQL_BINARY:
  1020.                 default:
  1021.                     if(lpd[i].cb > MAX_STRING_SIZE && returncode == SQL_SUCCESS)
  1022.                         DISPLAYERROR("returned data", "incorrect outlen");
  1023.                     same = TRUE; /* not checking returned data for binary */
  1024.             }
  1025.         if(!same)
  1026.             DISPLAYERROR("returned data", "invalid data");
  1027.         }
  1028.     }
  1029.  
  1030.     RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1031.  
  1032.     if(ind != cTypes + 1)
  1033.         DISPLAYERROR("SQLFetch", "Incorrect number of result rows");
  1034.  
  1035.     returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1036.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1037.  
  1038.     returncode = SQLFreeStmt(hstmt, SQL_UNBIND);
  1039.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1040.  
  1041.     returncode = SQLFreeStmt(hstmt, SQL_RESET_PARAMS);
  1042.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1043.  
  1044.     wsprintf(lpqt->sz, "select %s from %s where ", lpqt->szColNames,
  1045.         lpqt->szTableName);
  1046.  
  1047.     sdw = SQL_DATA_AT_EXEC;
  1048.  
  1049.     for(i = 0, w = 0; i < cTypes; i++) {
  1050.         pch = qtMakeData(ind, &rgFields[i], lpqt->szDataItem);
  1051.         if ((rgFields[i].fSearchable == SQL_SEARCHABLE ||
  1052.             rgFields[i].fSearchable == SQL_ALL_EXCEPT_LIKE) &&
  1053.             pch && *pch) {
  1054.             w++;
  1055.             switch(rgFields[i].wSQLType) {
  1056.                 case SQL_REAL:
  1057.                 case SQL_FLOAT:
  1058.                 case SQL_DOUBLE:
  1059.                     wsprintf(&lpqt->sz[lstrlen(lpqt->sz)], "%s < ? + 1 and ",
  1060.                         (LPSTR)rgFields[i].szFieldName);
  1061.                     break;
  1062.                 default:
  1063.                     wsprintf(&lpqt->sz[lstrlen(lpqt->sz)], "%s = ? and ",
  1064.                     (LPSTR)rgFields[i].szFieldName);
  1065.             }
  1066.  
  1067.             if(!fBindParam){
  1068.                 returncode = SQLSetParam(hstmt, w,
  1069.                     SQL_C_CHAR, rgFields[i].wSQLType,
  1070.                     rgFields[i].precision, rgFields[i].scale,
  1071.                     (LPSTR)(UDWORD)i, &sdw);
  1072.                 RETCHECK(SQL_SUCCESS, returncode, "SQLSetParam");
  1073.                 }
  1074.             else{
  1075.                 returncode = SQLBindParameter(hstmt, w, SQL_PARAM_INPUT,
  1076.                     SQL_C_CHAR, rgFields[i].wSQLType,
  1077.                     rgFields[i].precision, rgFields[i].scale,
  1078.                     (LPSTR)(UDWORD)i, 0, &sdw);
  1079.                 RETCHECK(SQL_SUCCESS, returncode, "SQLBindParameter");
  1080.                 }
  1081.  
  1082.             ind++;
  1083.         }
  1084.     }
  1085.     /* remove the final "and " */
  1086.     lpqt->sz[lstrlen(lpqt->sz) - 5] = '\0';
  1087.     lstrcpy(lpqt->szParamQuery, lpqt->sz);
  1088.  
  1089.     returncode = SQLPrepare(hstmt, lpqt->sz, SQL_NTS);
  1090.     RETCHECK(SQL_SUCCESS, returncode, "SQLPrepare");
  1091.  
  1092.     returncode = SQLExecute(hstmt);
  1093.     RETCHECK(SQL_NEED_DATA, returncode, "SQLExecute");
  1094.  
  1095.     udw = cTypes;
  1096.  
  1097.     for(i = 0; ; i++) {
  1098.         returncode = SQLParamData(hstmt, (PTR FAR *)&udw);
  1099.         if(returncode != SQL_NEED_DATA)
  1100.             break;
  1101.  
  1102.         if(udw < cTypes)
  1103.             pch = qtMakeData(cTypes, &rgFields[udw], lpqt->szDataItem);
  1104.         else {
  1105.             DISPLAYERROR("SQLParamData", "invalid rgbValue");
  1106.         }
  1107.  
  1108.         if(*pch) {
  1109.             udw = lstrlen(pch);
  1110.             returncode = SQLPutData(hstmt, pch, (SDWORD)lstrlen(pch));
  1111.             RETCHECK(SQL_SUCCESS, returncode, "SQLPutData");
  1112.         } else {
  1113.             returncode = SQLPutData(hstmt, (LPSTR)IGNORED, SQL_NULL_DATA);
  1114.             RETCHECK(SQL_SUCCESS, returncode, "SQLPutData");
  1115.         }
  1116.     }
  1117.     RETCHECK(SQL_SUCCESS, returncode, "SQLParamData");
  1118.  
  1119.     for(i = 0;; i++) {
  1120.         returncode = SQLFetch(hstmt);
  1121.  
  1122.         if(returncode != SQL_SUCCESS)
  1123.             break;
  1124.     }
  1125.     RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1126.  
  1127.     /* should have gotten 1 row back */
  1128.  
  1129.     if(i != 1) {
  1130.         DISPLAYERROR("Param/PutData", "incorrect number of rows returned");
  1131.     }
  1132.  
  1133.  
  1134.     returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1135.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1136.  
  1137.     /* > 1K query */
  1138.     wsprintf(lpqt->sz, "select %s from %s where ", lpqt->szColNames,
  1139.         lpqt->szTableName);
  1140.  
  1141.     for(i = 0; i < cTypes; i++) {
  1142.         if (rgFields[i].fSearchable == SQL_SEARCHABLE ||
  1143.             rgFields[i].fSearchable == SQL_ALL_EXCEPT_LIKE)
  1144.             break;
  1145.     }
  1146.  
  1147.     pch = qtMakeData(cTypes, &rgFields[i], lpqt->szDataItem);
  1148.     while(lstrlen(lpqt->sz) < 1024L) {                  
  1149.         int li=lstrlen(lpqt->sz);
  1150.         switch(rgFields[i].wSQLType) {
  1151.             case SQL_REAL:
  1152.             case SQL_FLOAT:
  1153.             case SQL_DOUBLE:
  1154.                 wsprintf(&lpqt->sz[lstrlen(lpqt->sz)], "%s < %s + 1 and ",
  1155.                     (LPSTR)rgFields[i].szFieldName, (LPSTR)pch);
  1156.                 break;
  1157.             default:
  1158.                 wsprintf(&lpqt->sz[lstrlen(lpqt->sz)], "%s = %s%s%s and ",
  1159.                 (LPSTR)rgFields[i].szFieldName, (LPSTR)rgFields[i].szPrefix, (LPSTR)pch, (LPSTR)rgFields[i].szSuffix);
  1160.                 break;
  1161.         }
  1162.     }
  1163.  
  1164.     /* remove the final "and " */
  1165.     lpqt->sz[lstrlen(lpqt->sz) - 5] = '\0';
  1166.                 
  1167.     returncode = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  1168.     RETCHECK(SQL_SUCCESS, returncode, "SQLExecDirect");
  1169.  
  1170.     for(i = 0;; i++) {
  1171.         returncode = SQLFetch(hstmt);
  1172.  
  1173.         if(returncode != SQL_SUCCESS)
  1174.             break;
  1175.     }
  1176.     RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1177.  
  1178.     /* should have gotten at least 1 row back */
  1179.  
  1180.     if(i < 1) {
  1181.         DISPLAYERROR("> 1K query", "incorrect number of rows returned");
  1182.     }
  1183.  
  1184.     
  1185.     /* SQLFreeStmt with SQL_CLOSE to re-use the hstmt */
  1186.  
  1187.     returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1188.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1189.  
  1190.     /* verify table shows up in SQLTables */
  1191.  
  1192.     returncode = SQLTables(hstmt, NULL, 0, NULL, 0, "q%",
  1193.         SQL_NTS, "'TABLE'", SQL_NTS); /* this call may return many 
  1194.             tables, as long as the one created earlier shows up it
  1195.             will pass. */
  1196.     RETCHECK(SQL_SUCCESS, returncode, "SQLTables");
  1197.  
  1198.     for(i = 0;; i++) {
  1199.         returncode = SQLFetch(hstmt);
  1200.         if(returncode != SQL_SUCCESS)
  1201.             break;
  1202.  
  1203.         /* column 3 is tablename */
  1204.         returncode = SQLGetData(hstmt, 3, SQL_C_CHAR, lpqt->sz, MAX_STRING_SIZE, NULL);
  1205.         RETCHECK(SQL_SUCCESS, returncode, "SQLGetData"); /* should not overflow
  1206.             and return SQL_SUCCESS_WITH_INFO because the buffer is larger than the
  1207.             table name */
  1208.         fFoundTable += 0 == lstrcmpi(lpqt->sz, lpqt->szTableName);
  1209.     }
  1210.  
  1211.     RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1212.  
  1213.     if(1 != fFoundTable) {
  1214.         DISPLAYERROR("SQLTables", "table not found");
  1215.     }
  1216.  
  1217.     returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1218.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1219.  
  1220.     /* create an index and verify that it is returned by SQLStatistics */
  1221.  
  1222.     lstrcpy(lpqt->szDataItem, lpqt->szTableName);
  1223.     lpqt->szDataItem[0] = 'i';
  1224.     for(i = 1; i < cTypes; i++)
  1225.         if(rgFields[i].wSQLType == SQL_INTEGER ||
  1226.             rgFields[i].wSQLType == SQL_SMALLINT)
  1227.             break;
  1228.     if(i == cTypes)
  1229.         i = 0;
  1230.  
  1231.     lstrcpy(lpqt->buf, rgFields[i].szFieldName);
  1232.     wsprintf(lpqt->sz, "create unique index %s on %s (%s)",
  1233.         lpqt->szDataItem, lpqt->szTableName, lpqt->buf);
  1234.  
  1235.     returncode = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  1236.     if(fIndex < 1)
  1237.         /* if this is minimal grammar, don't count on indexes being available */
  1238.         fIndex = returncode == SQL_SUCCESS;
  1239.     else
  1240.         RETCHECK(SQL_SUCCESS, returncode, "SQLExecDirect");
  1241.  
  1242.     /* this should return a keyset if one exists for the table. */
  1243.  
  1244.     returncode = SQLSpecialColumns(hstmt, SQL_BEST_ROWID, NULL, 0, NULL, 0,
  1245.         lpqt->szTableName, (SWORD)(lstrlen(lpqt->szTableName)), SQL_SCOPE_TRANSACTION,
  1246.         SQL_NULLABLE);
  1247.     RETCHECK(SQL_SUCCESS, returncode, "SQLSpecialColumns");
  1248.  
  1249.     for(i = 0;; i++){
  1250.         returncode = SQLFetch(hstmt);
  1251.         if(returncode != SQL_SUCCESS)
  1252.             break;
  1253.     }
  1254.  
  1255.     RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1256.  
  1257.     returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1258.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1259.  
  1260.     /* verify the index shows up in SQLStatistics */
  1261.  
  1262.     returncode = SQLStatistics(hstmt, NULL, 0, NULL, 0, lpqt->szTableName,
  1263.     SQL_NTS, SQL_INDEX_ALL, SQL_ENSURE);
  1264.     RETCHECK(SQL_SUCCESS, returncode, "SQLStatistics");
  1265.  
  1266.     fFoundTable = 0;
  1267.     for(i = 0;; i++) {
  1268.         returncode = SQLFetch(hstmt);
  1269.         if(returncode != SQL_SUCCESS)
  1270.             break;
  1271.  
  1272.         returncode = SQLGetData(hstmt, 3, SQL_C_CHAR, lpqt->sz, MAX_STRING_SIZE,
  1273.             NULL);
  1274.         RETCHECK(SQL_SUCCESS, returncode, "SQLGetData");
  1275.         if (lstrcmpi(lpqt->sz, lpqt->szTableName) == 0)
  1276.         {
  1277.             returncode = SQLGetData(hstmt, 6, SQL_C_CHAR, lpqt->sz, MAX_STRING_SIZE,
  1278.                 NULL);
  1279.             RETCHECK(SQL_SUCCESS, returncode, "SQLGetData");
  1280.             fFoundTable += 0 == lstrcmpi(lpqt->sz, lpqt->szDataItem);
  1281.         }
  1282.     }
  1283.  
  1284.     RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1285.  
  1286.     if(1 != fFoundTable && fIndex) {
  1287.         DISPLAYERROR("SQLStatistics", "index not returned");
  1288.     }
  1289.  
  1290.     if(i > 2 || i < 1) { /* one row represents original table, the other represents
  1291.                     the index */
  1292.         DISPLAYERROR("SQLStatistics", "too many rows");
  1293.     }
  1294.  
  1295.     returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1296.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1297.  
  1298.     for(i = 0; i < cTypes; i++) {
  1299.         if(rgFields[i].fSearchable == SQL_LIKE_ONLY ||
  1300.             rgFields[i].fSearchable == SQL_SEARCHABLE) {
  1301.             lstrcpy(lpqt->buf, rgFields[i].szFieldName);
  1302.             break;
  1303.         }
  1304.     }
  1305.     if(i < cTypes) {
  1306.     /* execute a query using like.  This query should return all records */
  1307.  
  1308.         wsprintf(lpqt->sz, "select * from %s where %s not like 'a'", lpqt->szTableName,
  1309.             lpqt->buf, lpqt->buf);
  1310.         /* this query should return all rows in the table */
  1311.  
  1312.         returncode = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  1313.         RETCHECK(SQL_SUCCESS, returncode, "SQLExecDirect");
  1314.  
  1315.         for(i = 0;; i++) {
  1316.             returncode = SQLFetch(hstmt);
  1317.             if(returncode != SQL_SUCCESS)
  1318.                 break;
  1319.  
  1320.             returncode = SQLGetData(hstmt, 1, SQL_C_CHAR, lpqt->sz, MAX_STRING_SIZE,
  1321.                 NULL);
  1322.             if(returncode != SQL_SUCCESS && returncode != SQL_SUCCESS_WITH_INFO)
  1323.                 RETCHECK(SQL_SUCCESS, returncode, "SQLGetData");
  1324.         }
  1325.  
  1326.         RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1327.  
  1328.         if(i != cTypes) {
  1329.             DISPLAYERROR("'LIKE' query", "incorrect number of result rows");
  1330.         }
  1331.     }
  1332.     /* SQLFreeStmt SQL_CLOSE to re-use it */
  1333.  
  1334.     returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1335.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1336.  
  1337.     /* attempt execution of Level 2 functionality */
  1338.  
  1339.     fLevel2 = FALSE;
  1340.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLFOREIGNKEYS,&fLevel2);
  1341.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1342.  
  1343.     if(!fLevel2) {
  1344.         returncode = SQLForeignKeys(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS, NULL, 0, NULL, 0, NULL, 0);
  1345.         if(!FindError("IM001"))
  1346.             DISPLAYERROR("SQLForeignKeys", "did not return Not supported message");
  1347.         RETCHECK(SQL_ERROR, returncode, "SQLForeignKeys");
  1348.     } else {
  1349.         returncode = SQLForeignKeys(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS, NULL, 0, NULL, 0, NULL, 0);
  1350.         RETCHECK(SQL_SUCCESS, returncode, "SQLForeignKeys");
  1351.         while(returncode == SQL_SUCCESS) {
  1352.             returncode = SQLFetch(hstmt);
  1353.         }
  1354.         RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1355.  
  1356.         returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1357.         RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1358.  
  1359.     }
  1360.  
  1361.     fLevel2 = FALSE;
  1362.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLBROWSECONNECT,&fLevel2);
  1363.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1364.  
  1365.     returncode = SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, &cMaxConnections, sizeof(int), NULL);
  1366.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetInfo");
  1367.  
  1368.     if(cMaxConnections != 1) {
  1369.         char szBCString[40];
  1370.         char szDSN[40];
  1371.         HDBC hdbcb;
  1372.         lstrcpy(szBCString, "DSN=");
  1373.         lstrcat(szBCString, pTestSource->szValidServer0);
  1374.         
  1375.         if(pTestSource->szValidServer0[0] == 0){
  1376.             returncode = SQLGetInfo(hdbc, SQL_DATA_SOURCE_NAME, &szDSN, 40, NULL);
  1377.             lstrcat(szBCString, szDSN);
  1378.             }
  1379.  
  1380.         if(!fLevel2) {
  1381.             HDBC thdbc;
  1382.  
  1383.             returncode = SQLAllocConnect(henv, &hdbcb);
  1384.             RETCHECK(SQL_SUCCESS, returncode, "SQLAllocConnect");
  1385.  
  1386.             returncode = SQLBrowseConnect(hdbcb, szBCString, SQL_NTS, NULL, 0, NULL);
  1387.             thdbc = hdbc;
  1388.             hdbc = hdbcb;
  1389.             if(!FindError("IM001"))
  1390.                 DISPLAYERROR("SQLBrowseConnect", "did not return Not supported message");
  1391.             RETCHECK(SQL_ERROR, returncode, "SQLBrowseConnect");
  1392.             hdbc = thdbc;
  1393.  
  1394.             returncode = SQLFreeConnect(hdbcb);
  1395.             RETCHECK(SQL_SUCCESS, returncode, "SQLFreeConnect");
  1396.         
  1397.         } else {
  1398.             returncode = SQLAllocConnect(henv, &hdbcb);
  1399.             RETCHECK(SQL_SUCCESS, returncode, "SQLAllocConnect");
  1400.  
  1401.             returncode = SQLBrowseConnect(hdbcb, szBCString, SQL_NTS, NULL, 0, NULL);
  1402.             RETCHECK(SQL_NEED_DATA, returncode, "SQLBrowseConnect");
  1403.  
  1404.             returncode = SQLDisconnect(hdbcb);
  1405.             RETCHECK(SQL_SUCCESS, returncode, "SQLDisconnect");
  1406.             returncode = SQLFreeConnect(hdbcb);
  1407.             RETCHECK(SQL_SUCCESS, returncode, "SQLFreeConnect");
  1408.         }
  1409.     }
  1410.  
  1411.     fLevel2 = FALSE;
  1412.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLDATASOURCES,&fLevel2);
  1413.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1414.  
  1415.     if(!fLevel2) {
  1416.         returncode = SQLDataSources(henv, SQL_FETCH_FIRST, NULL, 0, NULL, NULL, 0, NULL);
  1417.         if(!FindError("IM001"))
  1418.             DISPLAYERROR("SQLDataSources", "did not return Not supported message");
  1419.         RETCHECK(SQL_ERROR, returncode, "SQLDataSources");
  1420.     } else {
  1421.         returncode = SQLDataSources(henv, SQL_FETCH_FIRST, NULL, 0, NULL, NULL, 0, NULL);
  1422.         RETCHECK(SQL_SUCCESS, returncode, "SQLDataSources");
  1423.     }
  1424.  
  1425.     fLevel2 = FALSE;
  1426.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLDRIVERS,&fLevel2);
  1427.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1428.  
  1429.     if(!fLevel2) {
  1430.         returncode = SQLDrivers(henv, SQL_FETCH_FIRST, NULL, 0, NULL, NULL, 0, NULL);
  1431.         if(!FindError("IM001"))
  1432.             DISPLAYERROR("SQLDrivers", "did not return Not supported message");
  1433.         RETCHECK(SQL_ERROR, returncode, "SQLDataSources");
  1434.     } else {
  1435.         returncode = SQLDrivers(henv, SQL_FETCH_FIRST, NULL, 0, NULL, NULL, 0, NULL);
  1436.         if(returncode != SQL_SUCCESS)
  1437.             RETCHECK(SQL_SUCCESS_WITH_INFO, returncode, "SQLDrivers");
  1438.     }
  1439.  
  1440.     fLevel2 = FALSE;
  1441.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLMORERESULTS,&fLevel2);
  1442.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1443.  
  1444.     if(!fLevel2) {
  1445.         wsprintf(lpqt->sz, "select * from %s", lpqt->szTableName);
  1446.         returncode = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  1447.         RETCHECK(SQL_SUCCESS, returncode, "SQLExecDirect");
  1448.         returncode = SQLMoreResults(hstmt);
  1449.         if(!FindError("IM001"))
  1450.             DISPLAYERROR("SQLMoreResults", "did not return Not supported message");
  1451.         RETCHECK(SQL_ERROR, returncode, "SQLMoreResults");
  1452.     } else {
  1453.         wsprintf(lpqt->sz, "select * from %s", lpqt->szTableName);
  1454.         returncode = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  1455.         RETCHECK(SQL_SUCCESS, returncode, "SQLExecDirect");
  1456.         returncode = SQLMoreResults(hstmt);
  1457.         RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLMoreResults");
  1458.     }
  1459.  
  1460.     fLevel2 = FALSE;
  1461.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLNATIVESQL,&fLevel2);
  1462.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1463.  
  1464.     if(!fLevel2) {
  1465.         returncode = SQLNativeSql(hdbc, lpqt->sz, SQL_NTS, NULL, 0, NULL);
  1466.         if(!FindError("IM001"))
  1467.             DISPLAYERROR("SQLNativeSql", "did not return Not supported message");
  1468.         RETCHECK(SQL_ERROR, returncode, "SQLNativeSql");
  1469.     } else {
  1470.         returncode = SQLNativeSql(hdbc, lpqt->sz, SQL_NTS, NULL, 0, NULL);
  1471.         RETCHECK(SQL_SUCCESS, returncode, "SQLNativeSql");
  1472.     }
  1473.  
  1474.     fLevel2 = FALSE;
  1475.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLDESCRIBEPARAM,&fLevel2);
  1476.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1477.  
  1478.     if(!fLevel2) {
  1479.         returncode = SQLPrepare(hstmt, lpqt->szParamQuery, SQL_NTS);
  1480.         RETCHECK(SQL_SUCCESS, returncode, "SQLPrepare");
  1481.         returncode = SQLDescribeParam(hstmt, 1, NULL, NULL, NULL, NULL);
  1482.         if(!FindError("IM001"))
  1483.             DISPLAYERROR("SQLDescribeParam", "did not return Not supported message");
  1484.         RETCHECK(SQL_ERROR, returncode, "SQLDescribeParam");
  1485.     } else {
  1486.         returncode = SQLPrepare(hstmt, lpqt->szParamQuery, SQL_NTS);
  1487.         RETCHECK(SQL_SUCCESS, returncode, "SQLPrepare");
  1488.         returncode = SQLDescribeParam(hstmt, 1, NULL, NULL, NULL, NULL);
  1489.         RETCHECK(SQL_SUCCESS, returncode, "SQLDescribeParam");
  1490.     }
  1491.             
  1492.     fLevel2 = FALSE;
  1493.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLNUMPARAMS,&fLevel2);
  1494.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1495.  
  1496.     if(!fLevel2) {
  1497.         returncode = SQLNumParams(hstmt, NULL);
  1498.         if(!FindError("IM001"))
  1499.             DISPLAYERROR("SQLNumParams", "did not return Not supported message");
  1500.         RETCHECK(SQL_ERROR, returncode, "SQLNumParams");
  1501.     } else {
  1502.         returncode = SQLNumParams(hstmt, NULL);
  1503.         RETCHECK(SQL_SUCCESS, returncode, "SQLNumParams");
  1504.     }
  1505.  
  1506.     fLevel2 = FALSE;
  1507.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLPARAMOPTIONS,&fLevel2);
  1508.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1509.  
  1510.     if(!fLevel2) {
  1511.         returncode = SQLParamOptions(hstmt, 1, NULL);
  1512.         if(!FindError("IM001"))
  1513.             DISPLAYERROR("SQLParamOptions", "did not return Not supported message");
  1514.         RETCHECK(SQL_ERROR, returncode, "SQLParamOptions");
  1515.     } else {
  1516.         returncode = SQLParamOptions(hstmt, 1, NULL);
  1517.         RETCHECK(SQL_SUCCESS, returncode, "SQLParamOptions");
  1518.     }
  1519.  
  1520.     returncode = SQLFreeStmt(hstmt, SQL_DROP);
  1521.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1522.     returncode = SQLAllocStmt(hdbc, &hstmt);
  1523.     RETCHECK(SQL_SUCCESS, returncode, "SQLAllocStmt");
  1524.  
  1525.     fLevel2 = FALSE;
  1526.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLPRIMARYKEYS,&fLevel2);
  1527.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1528.  
  1529.     if(!fLevel2) {
  1530.         returncode = SQLPrimaryKeys(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS);
  1531.         if(!FindError("IM001"))
  1532.             DISPLAYERROR("SQLPrimaryKeys", "did not return Not supported message");
  1533.         RETCHECK(SQL_ERROR, returncode, "SQLPrimaryKeys");
  1534.     } else {
  1535.         returncode = SQLPrimaryKeys(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS);
  1536.         RETCHECK(SQL_SUCCESS, returncode, "SQLPrimaryKeys");
  1537.         while(returncode == SQL_SUCCESS) {
  1538.             returncode = SQLFetch(hstmt);
  1539.         }
  1540.         RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1541.  
  1542.         returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1543.         RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1544.     }
  1545.  
  1546.     fLevel2 = FALSE;
  1547.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLPROCEDURECOLUMNS,&fLevel2);
  1548.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1549.  
  1550.     if(!fLevel2) {
  1551.         returncode = SQLProcedureColumns(hstmt, NULL, 0, NULL, 0, NULL, 0, NULL, 0);
  1552.         if(!FindError("IM001"))
  1553.             DISPLAYERROR("SQLProcedureColumns", "did not return Not supported message");
  1554.         RETCHECK(SQL_ERROR, returncode, "SQLProcedureColumns");
  1555.     } else {
  1556.         returncode = SQLProcedureColumns(hstmt, NULL, 0, NULL, 0, NULL, 0, NULL, 0);
  1557.         RETCHECK(SQL_SUCCESS, returncode, "SQLProcedureColumns");
  1558.         while(returncode == SQL_SUCCESS) {
  1559.             returncode = SQLFetch(hstmt);
  1560.         }
  1561.         RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1562.  
  1563.         returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1564.         RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1565.     }
  1566.  
  1567.     fLevel2 = FALSE;
  1568.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLPROCEDURES,&fLevel2);
  1569.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1570.  
  1571.     if(!fLevel2) {
  1572.         returncode = SQLProcedures(hstmt, NULL, 0, NULL, 0, NULL, 0);
  1573.         if(!FindError("IM001"))
  1574.             DISPLAYERROR("SQLProcedures", "did not return Not supported message");
  1575.         RETCHECK(SQL_ERROR, returncode, "SQLProcedures");
  1576.     } else {
  1577.         returncode = SQLProcedures(hstmt, NULL, 0, NULL, 0, NULL, 0);
  1578.         RETCHECK(SQL_SUCCESS, returncode, "SQLProcedures");
  1579.         while(returncode == SQL_SUCCESS) {
  1580.             returncode = SQLFetch(hstmt);
  1581.         }
  1582.         RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1583.  
  1584.         returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1585.         RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1586.     }
  1587.  
  1588.     fLevel2 = FALSE;
  1589.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLTABLEPRIVILEGES,&fLevel2);
  1590.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1591.  
  1592.     if(!fLevel2) {
  1593.         returncode = SQLTablePrivileges(hstmt, NULL, 0, NULL, 0, NULL, 0);
  1594.         if(!FindError("IM001"))
  1595.             DISPLAYERROR("SQLTablePrivileges", "did not return Not supported message");
  1596.         RETCHECK(SQL_ERROR, returncode, "SQLTablePrivileges");
  1597.     } else {
  1598.         returncode = SQLTablePrivileges(hstmt, NULL, 0, NULL, 0, NULL, 0);
  1599.         RETCHECK(SQL_SUCCESS, returncode, "SQLTablePrivileges");
  1600.         while(returncode == SQL_SUCCESS) {
  1601.             returncode = SQLFetch(hstmt);
  1602.         }
  1603.         RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1604.  
  1605.         returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1606.         RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1607.     }
  1608.  
  1609.     fLevel2 = FALSE;
  1610.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLCOLUMNPRIVILEGES,&fLevel2);
  1611.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1612.  
  1613.     if(!fLevel2) {
  1614.         returncode = SQLColumnPrivileges(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS,
  1615.             NULL, 0);
  1616.         if(!FindError("IM001"))
  1617.             DISPLAYERROR("SQLColummPrivileges", "did not return Not supported message");
  1618.         RETCHECK(SQL_ERROR, returncode, "SQLColumnPrivileges");
  1619.     } else {
  1620.         returncode = SQLColumnPrivileges(hstmt, NULL, 0, NULL, 0, lpqt->szTableName, SQL_NTS,
  1621.             NULL, 0);
  1622.         RETCHECK(SQL_SUCCESS, returncode, "SQLColumnPrivileges");
  1623.         while(returncode == SQL_SUCCESS) {
  1624.             returncode = SQLFetch(hstmt);
  1625.         }
  1626.         RETCHECK(SQL_NO_DATA_FOUND, returncode, "SQLFetch");
  1627.  
  1628.         returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1629.         RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1630.     }
  1631.  
  1632.     fLevel2 = FALSE;
  1633.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLSETSCROLLOPTIONS,&fLevel2);
  1634.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1635.  
  1636.     if(!fLevel2) {
  1637.         returncode = SQLSetScrollOptions(hstmt, SQL_CONCUR_READ_ONLY, SQL_SCROLL_FORWARD_ONLY,
  1638.             1);
  1639.         if(!FindError("IM001"))
  1640.             DISPLAYERROR("SQLSetScrollOptionss", "did not return Not supported message");
  1641.         RETCHECK(SQL_ERROR, returncode, "SQLSetScrollOptions");
  1642.     } else {
  1643.         typedef struct SupportOptList {
  1644.             long Support;
  1645.             SDWORD Option;
  1646.             } SUPPORTOPTINFO;
  1647.  
  1648.         typedef struct SupportConcurList {
  1649.             long Support;
  1650.             UWORD Option;
  1651.             } SUPPORTCONCURINFO;
  1652.  
  1653.         SUPPORTOPTINFO OptionList[] = {SQL_SO_FORWARD_ONLY, SQL_SCROLL_FORWARD_ONLY,
  1654.                                             SQL_SO_KEYSET_DRIVEN, SQL_SCROLL_KEYSET_DRIVEN,
  1655.                                             SQL_SO_DYNAMIC, SQL_SCROLL_DYNAMIC};
  1656.  
  1657.         SUPPORTCONCURINFO ConcurList[] = {SQL_SCCO_READ_ONLY, SQL_CONCUR_READ_ONLY,
  1658.                                             SQL_SCCO_LOCK, SQL_CONCUR_LOCK,
  1659.                                             SQL_SCCO_OPT_TIMESTAMP, SQL_CONCUR_TIMESTAMP,
  1660.                                             SQL_SCCO_OPT_VALUES, SQL_CONCUR_VALUES};
  1661.  
  1662.         returncode = SQLGetInfo(hdbc, SQL_SCROLL_CONCURRENCY, &fSupportedCon, 4, NULL);
  1663.         RETCHECK(SQL_SUCCESS, returncode, "SQLGetInfo");
  1664.         returncode = SQLGetInfo(hdbc, SQL_SCROLL_OPTIONS, &fSupportedOpt, 4, NULL);
  1665.         RETCHECK(SQL_SUCCESS, returncode, "SQLGetInfo");
  1666.         for(i = 0; i < sizeof(OptionList) / sizeof(SUPPORTOPTINFO); i ++) {
  1667.             for(j = 0; j < sizeof(ConcurList) / sizeof(SUPPORTCONCURINFO); j++) {
  1668.                 if(fSupportedOpt & OptionList[i].Support && fSupportedCon & ConcurList[j].Support) {
  1669.                     if(!((ConcurList[j].Option == SQL_CONCUR_VALUES) && ((lpSI->vCursorLib == 
  1670.                             SQL_CUR_USE_IF_NEEDED) || (lpSI->vCursorLib == SQL_CUR_USE_ODBC)))){
  1671.                         returncode = SQLSetScrollOptions(hstmt, ConcurList[j].Option,
  1672.                             OptionList[i].Option, 1);
  1673.                         RETCHECK(SQL_SUCCESS, returncode, "SQLSetScrollOptions");
  1674.                     }
  1675.                 }
  1676.             }
  1677.         }
  1678.     }
  1679.  
  1680.     fLevel2 = FALSE;
  1681.     returncode = SQLGetFunctions(hdbc, SQL_API_SQLEXTENDEDFETCH,&fLevel2);
  1682.     RETCHECK(SQL_SUCCESS, returncode, "SQLGetFunctions");
  1683.  
  1684.     if(!fLevel2) {
  1685.         wsprintf(lpqt->sz, "select * from %s", lpqt->szTableName);
  1686.         returncode = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  1687.         RETCHECK(SQL_SUCCESS, returncode, "SQLExecDirect");
  1688.         returncode = SQLBindCol(hstmt, 1, SQL_C_BINARY, lpqt->sz, MAX_BIND_ARRAY_ELEMENT,
  1689.             NULL);
  1690.         RETCHECK(SQL_SUCCESS, returncode, "SQLBindCol");
  1691.  
  1692.         returncode = SQLExtendedFetch(hstmt, SQL_FETCH_FIRST, IGNORED, NULL, NULL);
  1693.         if(!FindError("IM001"))
  1694.             DISPLAYERROR("SQLExtendedFetch", "did not return Not supported message");
  1695.         RETCHECK(SQL_ERROR, returncode, "SQLExtendedFetch");
  1696.  
  1697.         returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1698.         RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1699.     } else {
  1700.         wsprintf(lpqt->sz, "select * from %s", lpqt->szTableName);
  1701.         returncode = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  1702.         RETCHECK(SQL_SUCCESS, returncode, "SQLExecDirect");
  1703.         returncode = SQLBindCol(hstmt, 1, SQL_C_BINARY, lpqt->sz, MAX_BIND_ARRAY_ELEMENT,
  1704.             NULL);
  1705.         RETCHECK(SQL_SUCCESS, returncode, "SQLBindCol");
  1706.  
  1707.         returncode = SQLGetStmtOption(hstmt,SQL_CURSOR_TYPE,&dwLen);
  1708.         RETCHECK(SQL_SUCCESS, returncode, "SQLGetStmtOption");
  1709.  
  1710.         if(dwLen != SQL_CURSOR_FORWARD_ONLY){
  1711.             returncode = SQLExtendedFetch(hstmt, SQL_FETCH_FIRST, IGNORED, NULL, NULL);
  1712.             RETCHECK(SQL_SUCCESS, returncode, "SQLExtendedFetch");
  1713.             }
  1714.         else{
  1715.             returncode = SQLExtendedFetch(hstmt, SQL_FETCH_FIRST, IGNORED, NULL, NULL);
  1716.             RETCHECK(SQL_ERROR, returncode, "SQLExtendedFetch");
  1717.             }
  1718.  
  1719.         returncode = SQLFreeStmt(hstmt, SQL_CLOSE);
  1720.         RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1721.     }
  1722.  
  1723.     /* cases added for 2.01 version of the SDK */
  1724.     fVer201 = FALSE;
  1725.     returncode = SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, lpqt->buf, MAX_STRING_SIZE, NULL);
  1726.     if(RETCHECK(SQL_SUCCESS, returncode, "SQLGetInfo")){
  1727.         pch = strtok(lpqt->buf, ".");
  1728.         if(!strncmp(pch, "02", 2)){
  1729.             pch = strtok(NULL, ".");
  1730.             if(!strncmp(pch, "00", 2))
  1731.                 DISPLAYERROR("SQLGetInfo", "Driver returned ODBC version 2.00 which is no longer supported.  Please upgrade to 2.01");
  1732.             if(!strncmp(pch, "01", 2)){
  1733.                 returncode = SQLGetInfo(hdbc, (UWORD)SQL_OJ_CAPABILITIES, &udw, (SWORD)(sizeof(udw)), NULL);
  1734.                 if(RETCHECK(SQL_SUCCESS, returncode, "SQLGetInfo")){
  1735.                     udw &= ~(SQL_OJ_LEFT | SQL_OJ_RIGHT | SQL_OJ_FULL | SQL_OJ_NESTED    |
  1736.                                 SQL_OJ_NOT_ORDERED | SQL_OJ_INNER | SQL_OJ_ALL_COMPARISON_OPS);
  1737.                     if(udw){
  1738.                         wsprintf(lpqt->buf, "Undefined flags return from SQLGetInfo(...SQL_OJ_CAPABILITIES...) = %lX", udw);
  1739.                         DISPLAYERROR("SQLGetInfo", lpqt->buf);
  1740.                         }
  1741.                     }
  1742.                 }
  1743.             }
  1744.         }
  1745.  
  1746.     returncode = SQLGetInfo(hdbc, SQL_OUTER_JOINS, lpqt->buf, MAX_STRING_SIZE, NULL);
  1747.     if(RETCHECK(SQL_SUCCESS, returncode, "SQLGetInfo")){
  1748.         *lpqt->buf = toupper(*lpqt->buf);
  1749.         if((!strncmp(lpqt->buf, "Y", 1)) && (!strncmp(lpqt->buf, "N", 1)))
  1750.             DISPLAYERROR("SQLGetInfo", "Driver returned an invalid value for SQLGetInfo(...SQL_OUTER_JOINS...).  The only valid values are \"Y\" and \"N\".");
  1751.         }
  1752.  
  1753.     /* end of cases added for 2.01 */
  1754.  
  1755.     /* finished testing, clean up */
  1756.         
  1757.     lstrcpy(lpqt->sz, "drop table ");
  1758.     lstrcat(lpqt->sz, lpqt->szTableName);
  1759.  
  1760.     returncode = SQLExecDirect(hstmt, lpqt->sz, SQL_NTS);
  1761.     if(!RETCHECK(SQL_SUCCESS, returncode, "SQLExecDirect"))
  1762.         szWrite("Unable to drop table", TRUE);
  1763.  
  1764.     /* SQLCancel has the same functionality as SQLFreeStmt w/ SQL_CLOSE
  1765.         in a non-asynchronous environment */
  1766.  
  1767.     returncode = SQLCancel(hstmt);
  1768.     RETCHECK(SQL_SUCCESS, returncode, "SQLCancel");
  1769.  
  1770.     returncode = SQLFreeStmt(hstmt, SQL_DROP);
  1771.     RETCHECK(SQL_SUCCESS, returncode, "SQLFreeStmt");
  1772.  
  1773.     if(*pTestSource->szValidServer0) { /* if the connection was made in the
  1774.                                         test, it should be disconnected
  1775.                         in the test, otherwise it should be left connected */
  1776.  
  1777.         returncode = SQLDisconnect(hdbc);
  1778.         RETCHECK(SQL_SUCCESS, returncode, "SQLDisconnect");
  1779.  
  1780.         returncode = SQLFreeConnect(hdbc);
  1781.         RETCHECK(SQL_SUCCESS, returncode, "SQLFreeConnect");
  1782.  
  1783.         returncode = SQLFreeEnv(henv);
  1784.         RETCHECK(SQL_SUCCESS, returncode, "SQLFreeEnv");
  1785.     }
  1786.  
  1787.     ReleaseMemory(lpd);
  1788.     ReleaseMemory(lpqt);
  1789.     ReleaseMemory(rgFields);
  1790.  
  1791.     pTestSource->cErrors = lpSI->failed;
  1792.  
  1793.     return;
  1794.  
  1795.  
  1796. ErrorRet:
  1797.  
  1798.     /* a failure in an ODBC function that prevents completion of the
  1799.         test - for example, connect to the server */
  1800.  
  1801.     szWrite("\t\t *** Unrecoverable Quick Test FAILURE ***", TRUE);
  1802.  
  1803.     ReleaseMemory(lpd);
  1804.     ReleaseMemory(lpqt);
  1805.     ReleaseMemory(rgFields);
  1806.  
  1807.     pTestSource->cErrors = ABORT;
  1808.  
  1809.     return;
  1810. }
  1811.  
  1812. LPSTR FAR PASCAL RetcodeToChar(RETCODE retcode, LPSTR buf)
  1813. {
  1814. switch (retcode) {
  1815.     case SQL_SUCCESS:
  1816.         lstrcpy (buf, "SQL_SUCCESS");
  1817.         break;
  1818.     case SQL_ERROR:
  1819.         lstrcpy (buf, "SQL_ERROR");
  1820.         break;
  1821.     case SQL_SUCCESS_WITH_INFO:
  1822.         lstrcpy (buf, "SQL_SUCCESS_WITH_INFO");
  1823.         break;
  1824.     case SQL_NO_DATA_FOUND:
  1825.         lstrcpy (buf, "SQL_NO_DATA_FOUND");
  1826.         break;
  1827.     case SQL_NEED_DATA:
  1828.         lstrcpy (buf, "SQL_NEED_DATA");
  1829.         break;
  1830.     case SQL_INVALID_HANDLE:
  1831.         lstrcpy (buf, "SQL_INVALID_HANDLE");
  1832.         break;
  1833.     case SQL_STILL_EXECUTING:
  1834.         lstrcpy (buf, "SQL_STILL_EXECUTING");
  1835.         break;
  1836.     default:
  1837.         lstrcpy(buf, "UNKNOWN RETURNCODE");
  1838. }
  1839.  
  1840. return buf;
  1841. }
  1842.  
  1843. #define STATE_SIZE 6
  1844. #define COMBINED_SIZE MAX_ERROR_SIZE + 30
  1845.  
  1846. void FAR PASCAL DisplayAllErrors()
  1847. {
  1848.     char buf[MAX_ERROR_SIZE];
  1849.     char largebuf[COMBINED_SIZE];
  1850.     char szState[STATE_SIZE];
  1851.     RETCODE returncode;
  1852.  
  1853.     for(returncode = SQLError(henv, NULL, NULL, szState, NULL, buf, MAX_ERROR_SIZE, NULL)
  1854.         ; returncode == SQL_SUCCESS || returncode == SQL_SUCCESS_WITH_INFO
  1855.         ; returncode = SQLError(henv, NULL, NULL, szState, NULL, buf, MAX_ERROR_SIZE, NULL)) {
  1856.         wsprintf(largebuf, "\tState: %s", (LPSTR)szState);
  1857.         szWrite(largebuf, TRUE);
  1858.         wsprintf(largebuf, "\tError: %s", (LPSTR)buf);
  1859.         szWrite(largebuf, TRUE);
  1860.     }
  1861.     for(returncode = SQLError(NULL, hdbc, NULL, szState, NULL, buf, MAX_ERROR_SIZE, NULL)
  1862.         ; returncode == SQL_SUCCESS || returncode == SQL_SUCCESS_WITH_INFO
  1863.         ; returncode = SQLError(NULL, hdbc, NULL, szState, NULL, buf, MAX_ERROR_SIZE, NULL)) {
  1864.         wsprintf(largebuf, "\tState: %s", (LPSTR)szState);
  1865.         szWrite(largebuf, TRUE);
  1866.         wsprintf(largebuf, "\tError: %s", (LPSTR)buf);
  1867.         szWrite(largebuf, TRUE);
  1868.     }
  1869.     for(returncode = SQLError(NULL, NULL, hstmt, szState, NULL, buf, MAX_ERROR_SIZE, NULL)
  1870.         ; returncode == SQL_SUCCESS || returncode == SQL_SUCCESS_WITH_INFO
  1871.         ; returncode = SQLError(NULL, NULL, hstmt, szState, NULL, buf, MAX_ERROR_SIZE, NULL)) {
  1872.         wsprintf(largebuf, "\tState: %s", (LPSTR)szState);
  1873.         szWrite(largebuf, TRUE);
  1874.         wsprintf(largebuf, "\tError: %s", (LPSTR)buf);
  1875.         szWrite(largebuf, TRUE);
  1876.     }
  1877. }
  1878.  
  1879. int FAR PASCAL ReturnCheck(RETCODE retExpected, RETCODE retReceived, LPSTR szFunction, LPSTR szFile, int iLine)
  1880. {
  1881.     char buf[MAX_STRING_SIZE];
  1882. //      extern int failed;
  1883.  
  1884.     if(retExpected == retReceived)
  1885.         return TRUE;
  1886.  
  1887.     szWrite("", TRUE);
  1888.  
  1889.     szWrite("\t", FALSE);
  1890.     szWrite(szFunction, TRUE);
  1891.  
  1892.     szWrite("\tExpected: ", FALSE);
  1893.     szWrite(RetcodeToChar(retExpected, buf), TRUE);
  1894.  
  1895.     szWrite("\tReceived: ", FALSE);
  1896.     szWrite(RetcodeToChar(retReceived, buf), TRUE);
  1897.  
  1898.     DisplayAllErrors();
  1899.  
  1900.     wsprintf(buf, "\t%s: %d", szFile, iLine);
  1901.     szWrite(buf, TRUE);
  1902.  
  1903.     szWrite("  --------  ", TRUE);
  1904.  
  1905.     lpSI->failed++;
  1906.  
  1907.     return FALSE;
  1908. }
  1909.  
  1910. void FAR PASCAL qtDisplayError(LPSTR szFunction, LPSTR buf, LPSTR szFile, int iLine)
  1911. {
  1912. //      extern int failed;
  1913.     char szTmp[MAX_STRING_SIZE];
  1914.  
  1915.     szWrite("", TRUE);
  1916.     szWrite("\t", FALSE);
  1917.     szWrite(szFunction, FALSE);
  1918.     szWrite("  FAILED", TRUE);
  1919.     szWrite("\t", FALSE);
  1920.     szWrite(buf, TRUE);
  1921.  
  1922.     wsprintf(szTmp, "\t%s: %d", szFile, iLine);
  1923.     szWrite(szTmp, TRUE);
  1924.  
  1925.     szWrite("  --------  ", TRUE);
  1926.  
  1927.     lpSI->failed++;
  1928.  
  1929.     return;
  1930. }
  1931.  
  1932. int FAR PASCAL FindError(LPSTR szFindState)
  1933. {
  1934.     char buf[MAX_STRING_SIZE];
  1935.     RETCODE returncode;
  1936.     char szState[6];
  1937.     int found = FALSE;
  1938.  
  1939.     for(returncode = SQLError(henv, NULL, NULL, szState, NULL, buf, MAX_STRING_SIZE, NULL)
  1940.         ; !found && (returncode == SQL_SUCCESS || returncode == SQL_SUCCESS_WITH_INFO)
  1941.         ; returncode = SQLError(henv, NULL, NULL, szState, NULL, buf, MAX_STRING_SIZE, NULL)) {
  1942.         found = lstrcmp(szState, szFindState) == 0;
  1943.     }
  1944.  
  1945.     for(returncode = SQLError(NULL, hdbc, NULL, szState, NULL, buf, MAX_STRING_SIZE, NULL)
  1946.         ; !found && (returncode == SQL_SUCCESS || returncode == SQL_SUCCESS_WITH_INFO)
  1947.         ; returncode = SQLError(NULL, hdbc, NULL, szState, NULL, buf, MAX_STRING_SIZE, NULL)) {
  1948.         found = lstrcmp(szState, szFindState) == 0;
  1949.     }
  1950.  
  1951.     for(returncode = SQLError(NULL, NULL, hstmt, szState, NULL, buf, MAX_STRING_SIZE, NULL)
  1952.         ; !found && (returncode == SQL_SUCCESS || returncode == SQL_SUCCESS_WITH_INFO)
  1953.         ; returncode = SQLError(NULL, NULL, hstmt, szState, NULL, buf, MAX_STRING_SIZE, NULL)) {
  1954.         found = lstrcmp(szState, szFindState) == 0;
  1955.     }
  1956.  
  1957.     return found;
  1958. }
  1959.  
  1960. char FAR PASCAL qtlower (char ch)
  1961. {
  1962.     if(ch >= 'A' && ch <= 'Z')
  1963.         return ch + 'a' - 'A';
  1964.     else
  1965.         return ch;
  1966. }
  1967.  
  1968. int FAR PASCAL qtestristr(LPCSTR szString, LPCSTR szFind)
  1969. {
  1970.     int i;
  1971.     LPSTR bufString = AllocateMemory(lstrlen(szString) + 1);
  1972.     LPSTR bufFind = AllocateMemory(lstrlen(szFind) + 1);
  1973.  
  1974.     i = 0;
  1975.     while(szString[i]) {
  1976.         bufString[i] = qtlower(szString[i]);
  1977.         i++;
  1978.     }
  1979.  
  1980.     i = 0;
  1981.     while(szFind[i]) {
  1982.         bufFind[i] = qtlower(szFind[i]);
  1983.         i++;
  1984.     }
  1985.  
  1986.     i = !!strstr(bufString, bufFind);
  1987.  
  1988.     ReleaseMemory(bufString);
  1989.     ReleaseMemory(bufFind);
  1990.  
  1991.     return i;
  1992.  
  1993. }
  1994.  
  1995. LPSTR FAR PASCAL qtMakeData(int row, FIELDINFO FAR *rgField, LPSTR buf)
  1996. {
  1997.     if(rgField->fAutoUpdate)
  1998.         return NULL;
  1999.  
  2000.     if(rgField->nullable && 0 == row) {
  2001.         lstrcpy(buf, "");
  2002.         return buf;
  2003.     }
  2004.  
  2005.     switch(rgField->wSQLType) {
  2006.         case SQL_CHAR:
  2007.         case SQL_VARCHAR:
  2008.         case SQL_LONGVARCHAR:
  2009.         case SQL_BINARY:
  2010.         case SQL_VARBINARY:
  2011.         case SQL_LONGVARBINARY:
  2012.             if(rgField->precision < 4)
  2013.                 wsprintf(buf, "%d", 1);
  2014.             else
  2015.                 wsprintf(buf, "%d%d", row, row);
  2016.             break;
  2017.         case SQL_DECIMAL:
  2018.         case SQL_NUMERIC:
  2019.         case SQL_REAL:
  2020.         case SQL_FLOAT:
  2021.         case SQL_DOUBLE:
  2022.             if(row == 2 && !rgField->fUnsigned) /* make the second row negative for variety */
  2023.                 wsprintf(buf, "-%d.%d", row, row);
  2024.             else
  2025.                 wsprintf(buf, "%d.%d", row, row);
  2026.             break;
  2027.  
  2028.         case SQL_BIT:
  2029.             if(row > 2)
  2030.                 wsprintf(buf, "%d", 1);
  2031.             else
  2032.                 wsprintf(buf, "%d", 0);
  2033.  
  2034.             break;
  2035.  
  2036.         case SQL_SMALLINT:
  2037.         case SQL_INTEGER:
  2038.         case SQL_TINYINT:
  2039.         case SQL_BIGINT:
  2040.             if(row == 2 && !rgField->fUnsigned) /* make the second row negative for variety */
  2041.                 wsprintf(buf, "-%d", row);
  2042.             else
  2043.                 wsprintf(buf, "%d", row);
  2044.             break;
  2045.  
  2046.         case SQL_TIME:
  2047.             wsprintf(buf, "{t '01:%02d:%02d'}", row % 60, row % 60);
  2048.             break;
  2049.         case SQL_DATE:
  2050.             wsprintf(buf, "{d '1994-%02d-%02d'}", (row % 12) + 1, (row % 30) + 1);
  2051.             break;
  2052.         case SQL_TIMESTAMP:
  2053.             wsprintf(buf, "{ts '1994-%02d-%02d 01:%02d:%02d'}", (row % 12) + 1, (row % 30) + 1, row % 60, row % 60);
  2054.             break;
  2055.     }
  2056.     return buf;
  2057. }
  2058.  
  2059.  
  2060. VOID WINAPI szWrite(LPSTR szStr, BOOL fNewLine)
  2061. {
  2062.     szLogPrintf(lpSI, FALSE, szStr);
  2063.     if(fNewLine)
  2064.         szLogPrintf(lpSI, FALSE, (LPSTR)"\r\n");
  2065. }
  2066.