LCOV - code coverage report
Current view: top level - src/odbc/unittests - genparams.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 302 309 97.7 %
Date: 2024-04-18 21:21:48 Functions: 7 7 100.0 %

          Line data    Source code
       1             : #include "common.h"
       2             : #include <assert.h>
       3             : #include <time.h>
       4             : 
       5             : /* Test various type from odbc and to odbc */
       6             : 
       7             : /*
       8             :  * This test is useful to test odbc_sql2tds function using TestInput
       9             :  * odbc_sql2tds have some particular cases:
      10             :  * (1) char    -> char     handled differently with encoding problems
      11             :  * (2) date    -> *        different format TODO
      12             :  * (3) numeric -> *        different format
      13             :  * (4) *       -> numeric  take precision and scale from ipd TODO
      14             :  * (5) *       -> char     test wide
      15             :  * (6) *       -> blob     test wchar and ntext
      16             :  * (7) *       -> binary   test also with wchar
      17             :  * (8) binary  -> *        test also with wchar
      18             :  * Also we have to check normal char and wide char
      19             :  */
      20             : 
      21             : #ifdef TDS_NO_DM
      22             : static const char tds_no_dm = 1;
      23             : #else
      24             : static const char tds_no_dm = 0;
      25             : #endif
      26             : 
      27             : static char precision = 18;
      28             : static char exec_direct = 0;
      29             : static char prepare_before = 0;
      30             : static char use_cursors = 0;
      31             : static int only_test = 0;
      32             : 
      33             : static const char *
      34        5454 : split_collate(ODBC_BUF** buf, const char **type)
      35             : {
      36        5454 :         const char *collate = "", *p;
      37             : 
      38        5454 :         if ((p = strstr(*type, " COLLATE ")) != NULL) {
      39         114 :                 if (odbc_db_is_microsoft())
      40         108 :                         collate = p;
      41         114 :                 *type = odbc_buf_asprintf(buf, "%.*s", (int) (p - *type), *type);
      42             :         }
      43        5454 :         return collate;
      44             : }
      45             : 
      46             : static int
      47         510 : TestOutput(const char *type, const char *value_to_convert, SQLSMALLINT out_c_type, SQLSMALLINT out_sql_type, const char *expected)
      48             : {
      49             :         char sbuf[1024];
      50             :         unsigned char out_buf[256];
      51         510 :         SQLLEN out_len = 0;
      52             :         const char *sep;
      53             :         const char *collate;
      54             : 
      55         510 :         odbc_reset_statement();
      56             : 
      57             :         /* build store procedure to test */
      58         510 :         odbc_command("IF OBJECT_ID('spTestProc') IS NOT NULL DROP PROC spTestProc");
      59         510 :         sep = "'";
      60         510 :         if (strncmp(value_to_convert, "0x", 2) == 0 || strncmp(value_to_convert, "NCHAR(", 6) == 0)
      61          72 :                 sep = "";
      62         510 :         collate = split_collate(&odbc_buf, &type);
      63         510 :         sprintf(sbuf, "CREATE PROC spTestProc @i %s OUTPUT AS SELECT @i = CONVERT(%s, %s%s%s)%s",
      64             :                 type, type, sep, value_to_convert, sep, collate);
      65         510 :         odbc_command(sbuf);
      66         510 :         memset(out_buf, 0, sizeof(out_buf));
      67             : 
      68         510 :         if (use_cursors) {
      69         228 :                 odbc_reset_statement();
      70         228 :                 CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S");
      71         228 :                 CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S");
      72             :         }
      73             : 
      74             :         /* bind parameter */
      75         510 :         if (exec_direct) {
      76         170 :                 CHKBindParameter(1, SQL_PARAM_OUTPUT, out_c_type, out_sql_type, precision, 0, out_buf,
      77             :                              sizeof(out_buf), &out_len, "S");
      78             : 
      79             :                 /* call store procedure */
      80         170 :                 CHKExecDirect(T("{call spTestProc(?)}"), SQL_NTS, "S");
      81             :         } else {
      82         340 :                 if (prepare_before)
      83         170 :                         CHKPrepare(T("{call spTestProc(?)}"), SQL_NTS, "S");
      84             : 
      85         340 :                 CHKBindParameter(1, SQL_PARAM_OUTPUT, out_c_type, out_sql_type, precision, 0, out_buf,
      86             :                              sizeof(out_buf), &out_len, "S");
      87             : 
      88         340 :                 if (!prepare_before)
      89         170 :                         CHKPrepare(T("{call spTestProc(?)}"), SQL_NTS, "S");
      90             : 
      91         340 :                 CHKExecute("S");
      92             :         }
      93             : 
      94             :         /*
      95             :          * MS OBDC requires it cause first recordset is a recordset with a
      96             :          * warning caused by the way it execute RPC (via EXEC statement)
      97             :          */
      98         510 :         if (use_cursors && !odbc_driver_is_freetds())
      99           0 :                 SQLMoreResults(odbc_stmt);
     100             : 
     101             :         /* test results */
     102         510 :         odbc_c2string(sbuf, out_c_type, out_buf, out_len);
     103             : 
     104         510 :         if (strcmp(sbuf, expected) != 0) {
     105          30 :                 if (only_test) {
     106          30 :                         odbc_command("drop proc spTestProc");
     107          30 :                         ODBC_FREE();
     108          30 :                         return 1;
     109             :                 }
     110           0 :                 fprintf(stderr, "Wrong result\n  Got: %s\n  Expected: %s\n", sbuf, expected);
     111           0 :                 exit(1);
     112             :         }
     113         480 :         only_test = 0;
     114         480 :         odbc_command("drop proc spTestProc");
     115         480 :         ODBC_FREE();
     116         480 :         return 0;
     117             : }
     118             : 
     119             : static char check_truncation = 0;
     120             : static char use_nts = 0;
     121             : 
     122             : /**
     123             :  * Test a parameter as input to prepared statement
     124             :  *
     125             :  * "value_to_convert" will be inserted as database type "type" and C type "out_c_type" into a column of
     126             :  * database type "param_type" and SQL type "out_sql_type". Then a select statement check that the column
     127             :  * in the database is the same as "value_to_convert".
     128             :  * "value_to_convert" can also contain a syntax like "input -> output", in this case the initial inserted
     129             :  * value is "input" and the final check will check for "output".
     130             :  */
     131             : static void
     132        2472 : TestInput(SQLSMALLINT out_c_type, const char *type, SQLSMALLINT out_sql_type, const char *param_type, const char *value_to_convert)
     133             : {
     134             :         char sbuf[1024];
     135             :         unsigned char out_buf[256];
     136        2472 :         SQLLEN out_len = 0;
     137        2472 :         const char *expected = value_to_convert;
     138        2472 :         size_t value_len = strlen(value_to_convert);
     139             :         const char *p;
     140        2472 :         const char *sep = "'";
     141             :         const char *collate;
     142             : 
     143        2472 :         odbc_reset_statement();
     144             : 
     145             :         /* execute a select to get data as wire */
     146        2472 :         if ((p = strstr(value_to_convert, " -> ")) != NULL) {
     147         996 :                 value_len = p - value_to_convert;
     148         996 :                 expected = p + 4;
     149             :         }
     150        2472 :         if (value_len >= 2 && strncmp(value_to_convert, "0x", 2) == 0)
     151         300 :                 sep = "";
     152        2472 :         collate = split_collate(&odbc_buf, &type);
     153        2472 :         sprintf(sbuf, "SELECT CONVERT(%s, %s%.*s%s%s)", type, sep, (int) value_len, value_to_convert, sep, collate);
     154        2472 :         odbc_command(sbuf);
     155        2472 :         SQLBindCol(odbc_stmt, 1, out_c_type, out_buf, sizeof(out_buf), &out_len);
     156        2472 :         CHKFetch("SI");
     157        2472 :         CHKFetch("No");
     158        2472 :         CHKMoreResults("No");
     159        2472 :         if (use_nts) {
     160          72 :                 out_len = SQL_NTS;
     161          72 :                 use_nts = 0;
     162             :         }
     163             : 
     164             :         /* create a table with a column of that type */
     165        2472 :         odbc_reset_statement();
     166        2472 :         collate = split_collate(&odbc_buf, &param_type);
     167        2472 :         sprintf(sbuf, "CREATE TABLE #tmp_insert (col %s%s)", param_type, collate);
     168        2472 :         odbc_command(sbuf);
     169             : 
     170        2472 :         if (use_cursors) {
     171        1110 :                 odbc_reset_statement();
     172        1110 :                 CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S");
     173        1110 :                 CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S");
     174             :         }
     175             : 
     176             :         /* insert data using prepared statements */
     177        2472 :         sprintf(sbuf, "INSERT INTO #tmp_insert VALUES(?)");
     178        2472 :         if (exec_direct) {
     179         824 :                 CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, out_buf, sizeof(out_buf), &out_len, "S");
     180             : 
     181         824 :                 if (check_truncation)
     182           0 :                         CHKExecDirect(T(sbuf), SQL_NTS, "E");
     183             :                 else
     184         824 :                         CHKExecDirect(T(sbuf), SQL_NTS, "SNo");
     185             :         } else {
     186        1648 :                 if (prepare_before)
     187         824 :                         CHKPrepare(T(sbuf), SQL_NTS, "S");
     188             : 
     189        1648 :                 CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, out_buf, sizeof(out_buf), &out_len, "S");
     190             : 
     191        1648 :                 if (!prepare_before)
     192         824 :                         CHKPrepare(T(sbuf), SQL_NTS, "S");
     193             : 
     194        1648 :                 if (check_truncation)
     195           0 :                         CHKExecute("E");
     196             :                 else
     197        1648 :                         CHKExecute("SNo");
     198             :         }
     199             : 
     200             :         /* check if row is present */
     201        2472 :         if (!check_truncation) {
     202             :                 char *p;
     203             : 
     204        2472 :                 odbc_reset_statement();
     205        2472 :                 sep = "'";
     206        2472 :                 if (strncmp(expected, "0x", 2) == 0)
     207         144 :                         sep = "";
     208             : 
     209        2472 :                 strcpy(sbuf, "SELECT * FROM #tmp_insert WHERE ");
     210        2472 :                 p = strchr(sbuf, 0);
     211        2472 :                 if (strcmp(param_type, "TEXT") == 0)
     212         210 :                         sprintf(p, "CONVERT(VARCHAR(255), col) = CONVERT(VARCHAR(255), %s%s%s)", sep, expected, sep);
     213        2262 :                 else if (strcmp(param_type, "NTEXT") == 0)
     214         288 :                         sprintf(p, "CONVERT(NVARCHAR(2000), col) = CONVERT(NVARCHAR(2000), %s%s%s)", sep, expected, sep);
     215        1974 :                 else if (strcmp(param_type, "IMAGE") == 0)
     216          42 :                         sprintf(p, "CONVERT(VARBINARY(255), col) = CONVERT(VARBINARY(255), %s%s%s)", sep, expected, sep);
     217             :                 else
     218        1932 :                         sprintf(p, "col = CONVERT(%s, %s%s%s)", param_type, sep, expected, sep);
     219        2472 :                 odbc_command(sbuf);
     220             : 
     221        2472 :                 CHKFetch("S");
     222        2472 :                 CHKFetch("No");
     223        2472 :                 CHKMoreResults("No");
     224             :         }
     225        2472 :         check_truncation = 0;
     226        2472 :         odbc_command("DROP TABLE #tmp_insert");
     227        2472 :         ODBC_FREE();
     228        2472 : }
     229             : 
     230             : /* stripped down version of TestInput for NULLs */
     231             : static void
     232         372 : NullInput(SQLSMALLINT out_c_type, SQLSMALLINT out_sql_type, const char *param_type)
     233             : {
     234             :         char sbuf[1024];
     235         372 :         SQLLEN out_len = SQL_NULL_DATA;
     236             : 
     237         372 :         odbc_reset_statement();
     238             : 
     239             :         /* create a table with a column of that type */
     240         372 :         odbc_reset_statement();
     241         372 :         sprintf(sbuf, "CREATE TABLE #tmp_insert (col %s NULL)", param_type);
     242         372 :         odbc_command(sbuf);
     243             : 
     244         372 :         if (use_cursors) {
     245         162 :                 odbc_reset_statement();
     246         162 :                 CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S");
     247         162 :                 CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S");
     248             :         }
     249             : 
     250             :         /* insert data using prepared statements */
     251         372 :         sprintf(sbuf, "INSERT INTO #tmp_insert VALUES(?)");
     252         372 :         if (exec_direct) {
     253         124 :                 CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, NULL, 1, &out_len, "S");
     254             : 
     255         124 :                 CHKExecDirect(T(sbuf), SQL_NTS, "SNo");
     256             :         } else {
     257         248 :                 if (prepare_before)
     258         124 :                         CHKPrepare(T(sbuf), SQL_NTS, "S");
     259             : 
     260         248 :                 CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, NULL, 1, &out_len, "S");
     261             : 
     262         248 :                 if (!prepare_before)
     263         124 :                         CHKPrepare(T(sbuf), SQL_NTS, "S");
     264             : 
     265         248 :                 CHKExecute("SNo");
     266             :         }
     267             : 
     268             :         /* check if row is present */
     269         372 :         odbc_reset_statement();
     270         372 :         if (!odbc_db_is_microsoft() && strcmp(param_type, "TEXT") == 0)
     271          18 :                 odbc_command("SELECT * FROM #tmp_insert WHERE DATALENGTH(col) = 0 OR DATALENGTH(col) IS NULL");
     272             :         else
     273         354 :                 odbc_command("SELECT * FROM #tmp_insert WHERE col IS NULL");
     274             : 
     275         372 :         CHKFetch("S");
     276         372 :         CHKFetch("No");
     277         372 :         CHKMoreResults("No");
     278         372 :         odbc_command("DROP TABLE #tmp_insert");
     279         372 :         ODBC_FREE();
     280         372 : }
     281             : 
     282             : 
     283             : static int big_endian = 1;
     284             : 
     285             : static const char*
     286         114 : pack(const char *fmt, ...)
     287             : {
     288             :         static char out[80];
     289         114 :         char *p = out;
     290             : 
     291             :         va_list v;
     292         114 :         va_start(v, fmt);
     293         612 :         for (; *fmt; ++fmt) {
     294         498 :                 unsigned n = va_arg(v, unsigned);
     295         498 :                 int i, l = 2;
     296             : 
     297         498 :                 assert(p - out + 8 < sizeof(out));
     298         498 :                 switch (*fmt) {
     299         174 :                 case 'l':
     300         174 :                         l += 2;
     301         498 :                 case 's':
     302        1842 :                         for (i = 0; i < l; ++i) {
     303        1344 :                                 sprintf(p, "%02X", (n >> (8*(big_endian ? l-1-i : i))) & 0xffu);
     304        1344 :                                 p += 2;
     305             :                         }
     306             :                         break;
     307             :                 default:
     308           0 :                         assert(0);
     309             :                 }
     310             :         }
     311         114 :         *p = 0;
     312         114 :         va_end(v);
     313         114 :         return out;
     314             : }
     315             : 
     316             : static void
     317          42 : AllTests(void)
     318             : {
     319             :         struct tm *ltime;
     320             :         char buf[80];
     321             :         time_t curr_time;
     322             : 
     323             :         SQLINTEGER y, m, d;
     324             :         char date[128];
     325             : 
     326          42 :         printf("use_cursors %d exec_direct %d prepare_before %d\n", use_cursors, exec_direct, prepare_before);
     327             : 
     328             :         /* test some NULLs */
     329          42 :         NullInput(SQL_C_CHAR, SQL_VARCHAR, "VARCHAR(100)");
     330          42 :         NullInput(SQL_C_CHAR, SQL_LONGVARCHAR, "TEXT");
     331          42 :         NullInput(SQL_C_LONG, SQL_INTEGER, "INTEGER");
     332          42 :         NullInput(SQL_C_LONG, SQL_LONGVARCHAR, "TEXT");
     333          42 :         NullInput(SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, "DATETIME");
     334          42 :         NullInput(SQL_C_FLOAT,  SQL_REAL, "FLOAT");
     335          42 :         NullInput(SQL_C_NUMERIC, SQL_LONGVARCHAR, "TEXT");
     336          42 :         if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u)
     337          36 :                 NullInput(SQL_C_BIT, SQL_BIT, "BIT");
     338          42 :         NullInput(SQL_C_DOUBLE, SQL_DOUBLE, "MONEY");
     339             : 
     340             :         /* FIXME why should return 38 0 as precision and scale ?? correct ?? */
     341          42 :         precision = 18;
     342          42 :         TestOutput("NUMERIC(18,2)", "123", SQL_C_NUMERIC, SQL_NUMERIC, "18 0 1 7B");
     343          42 :         TestOutput("DECIMAL(18,2)", "123", SQL_C_NUMERIC, SQL_DECIMAL, "18 0 1 7B");
     344          42 :         precision = 38;
     345          42 :         TestOutput("NUMERIC(18,2)", "123", SQL_C_NUMERIC, SQL_NUMERIC, "38 0 1 7B");
     346          42 :         TestInput(SQL_C_LONG, "INTEGER", SQL_VARCHAR, "VARCHAR(20)", "12345");
     347          42 :         TestInput(SQL_C_LONG, "INTEGER", SQL_LONGVARCHAR, "TEXT", "12345");
     348             :         /*
     349             :          * MS driver behavior for output parameters is different
     350             :          * former returns "313233" while newer "333133323333"
     351             :          */
     352          42 :         if (odbc_driver_is_freetds())
     353          42 :                 TestOutput("VARCHAR(20)", "313233", SQL_C_BINARY, SQL_VARCHAR, "333133323333");
     354             : 
     355          42 :         only_test = 1;
     356          42 :         precision = 3;
     357          42 :         if (TestOutput("DATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ssssssl", 2004, 2, 24, 15, 16, 17, 0))) {
     358             :                 /* FIXME our driver ignore precision for date */
     359          30 :                 precision = 3;
     360             :                 /* Some MS driver incorrectly prepare with smalldatetime*/
     361          30 :                 if (!use_cursors || odbc_driver_is_freetds()) {
     362          30 :                                 TestOutput("DATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ll", 0x9497, 0xFBAA2C));
     363             :                 }
     364          30 :                 TestOutput("SMALLDATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ll", 0x9497, 0xFB9640));
     365             :         } else {
     366          12 :                 TestOutput("SMALLDATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ssssssl", 2004, 2, 24, 15, 16, 0, 0));
     367             :         }
     368          42 :         TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34");
     369             : 
     370             :         /* test timestamp millisecond round off */
     371          42 :         TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34.001 -> 2005-07-22 09:51:34.000");
     372          42 :         TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34.002 -> 2005-07-22 09:51:34.003");
     373          42 :         TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34.003 -> 2005-07-22 09:51:34.003");
     374          42 :         TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34.004 -> 2005-07-22 09:51:34.003");
     375          42 :         TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34.005 -> 2005-07-22 09:51:34.007");
     376          42 :         TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34.006 -> 2005-07-22 09:51:34.007");
     377             : 
     378             :         /* FIXME on ms driver first SQLFetch return SUCCESS_WITH_INFO for truncation error */
     379          42 :         TestInput(SQL_C_TYPE_DATE, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 13:02:03 -> 2005-07-22 00:00:00");
     380             : 
     381             :         /* replace date information with current date */
     382          42 :         time(&curr_time);
     383          42 :         ltime = localtime(&curr_time);
     384          42 :         y = ltime->tm_year + 1900;
     385          42 :         m = ltime->tm_mon + 1;
     386          42 :         d = ltime->tm_mday;
     387             :         /* server concept of data can be different so try ask to server */
     388          42 :         odbc_command("SELECT GETDATE()");
     389          42 :         SQLBindCol(odbc_stmt, 1, SQL_C_CHAR, date, sizeof(date), NULL);
     390          42 :         if (SQLFetch(odbc_stmt) == SQL_SUCCESS) {
     391             :                 int a, b, c;
     392          42 :                 if (sscanf(date, "%d-%d-%d", &a, &b, &c) == 3) {
     393          42 :                         y = a;
     394          42 :                         m = b;
     395          42 :                         d = c;
     396             :                 }
     397             :         }
     398          42 :         SQLFetch(odbc_stmt);
     399          42 :         SQLMoreResults(odbc_stmt);
     400          42 :         SQLFreeStmt(odbc_stmt, SQL_UNBIND);
     401          42 :         sprintf(buf, "2003-07-22 13:02:03 -> %04d-%02d-%02d 13:02:03", (int) y, (int) m, (int) d);
     402          42 :         TestInput(SQL_C_TYPE_TIME, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", buf);
     403             : 
     404          42 :         TestInput(SQL_C_FLOAT,  "FLOAT", SQL_REAL, "FLOAT", "1234.25");
     405          42 :         TestInput(SQL_C_DOUBLE, "REAL", SQL_REAL, "FLOAT", "-1234.25");
     406          42 :         TestInput(SQL_C_FLOAT,  "REAL", SQL_REAL, "FLOAT", "1234.25");
     407          42 :         TestInput(SQL_C_DOUBLE, "FLOAT", SQL_REAL, "FLOAT", "-1234.25");
     408          42 :         TestInput(SQL_C_FLOAT,  "FLOAT", SQL_FLOAT, "FLOAT", "1234.25");
     409          42 :         TestInput(SQL_C_DOUBLE, "REAL", SQL_FLOAT, "FLOAT", "-1234.25");
     410          42 :         TestInput(SQL_C_FLOAT,  "FLOAT", SQL_DOUBLE, "FLOAT", "1234.25");
     411          42 :         TestInput(SQL_C_DOUBLE, "REAL", SQL_DOUBLE, "FLOAT", "-1234.25");
     412             : 
     413          42 :         TestInput(SQL_C_UTINYINT, "TINYINT", SQL_TINYINT, "TINYINT", "231");
     414             : 
     415          42 :         TestInput(SQL_C_NUMERIC, "NUMERIC(20,3)", SQL_NUMERIC, "NUMERIC(20,3)", "765432.2 -> 765432");
     416          42 :         TestInput(SQL_C_NUMERIC, "NUMERIC(20,3)", SQL_VARCHAR, "VARCHAR(20)", "578246.234 -> 578246");
     417          42 :         TestInput(SQL_C_NUMERIC, "NUMERIC(20,3)", SQL_LONGVARCHAR, "TEXT", "578246.234 -> 578246");
     418             : 
     419          42 :         TestInput(SQL_C_CHAR, "VARCHAR(100)", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
     420          42 :         TestInput(SQL_C_CHAR, "TEXT COLLATE Latin1_General_CI_AS", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
     421          42 :         TestInput(SQL_C_CHAR, "VARCHAR(100)", SQL_LONGVARBINARY, "IMAGE", "4145544F -> AETO");
     422          42 :         TestInput(SQL_C_BINARY, "VARBINARY(100)", SQL_VARCHAR, "VARCHAR(20)", "0x4145544F -> AETO");
     423          42 :         TestInput(SQL_C_BINARY, "IMAGE", SQL_VARCHAR, "VARCHAR(20)", "0x4145544F -> AETO");
     424             : 
     425          42 :         TestInput(SQL_C_BIT, "BIT", SQL_BIT, "BIT", "0");
     426          42 :         TestInput(SQL_C_BIT, "BIT", SQL_BIT, "BIT", "1");
     427             : 
     428          42 :         TestInput(SQL_C_DOUBLE, "MONEY", SQL_DOUBLE, "MONEY", "123.34");
     429             : 
     430          42 :         TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_VARCHAR, "VARCHAR(20)", "1EasyTest");
     431          42 :         TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_LONGVARCHAR, "TEXT", "1EasyTest");
     432          42 :         TestInput(SQL_C_WCHAR, "VARCHAR(10)", SQL_VARCHAR, "VARCHAR(10)", "Test 12345");
     433          42 :         TestInput(SQL_C_WCHAR, "VARCHAR(10)", SQL_LONGVARCHAR, "TEXT", "Test 12345");
     434             :         /* TODO use collate in syntax if available */
     435          42 :         TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_VARCHAR, "VARCHAR(20)", "me\xf4");
     436          42 :         TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_LONGVARCHAR, "TEXT", "me\xf4");
     437             : 
     438          42 :         precision = 6;
     439             :         /* output from char with conversions */
     440          42 :         TestOutput("VARCHAR(20)", "foo test", SQL_C_CHAR, SQL_VARCHAR, "6 foo te");
     441             :         /* TODO use collate in syntax if available */
     442             :         /* while usually on Microsoft database this encoding is valid on Sybase the database
     443             :          * could use UTF-8 encoding where \xf8\xf9 is an invalid encoded string */
     444          42 :         if (odbc_db_is_microsoft() && odbc_tds_version() > 0x700)
     445          36 :                 TestOutput("VARCHAR(20) COLLATE Latin1_General_CI_AS", "NCHAR(0xf8) + NCHAR(0xf9)", SQL_C_CHAR, SQL_VARCHAR, "2 \xf8\xf9");
     446             : 
     447             :         /* MSSQL 2000 using ptotocol 7.1+ */
     448          42 :         if ((odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u && odbc_tds_version() > 0x700)
     449           6 :             || (!odbc_db_is_microsoft() && strncmp(odbc_db_version(), "15.00.", 6) >= 0)) {
     450          42 :                 TestOutput("BIGINT", "-987654321065432", SQL_C_BINARY, SQL_BIGINT, big_endian ? "FFFC7DBBCF083228" : "283208CFBB7DFCFF");
     451          42 :                 TestInput(SQL_C_SBIGINT, "BIGINT", SQL_BIGINT, "BIGINT", "-12345678901234");
     452             :         }
     453             :         /* MSSQL 2000 */
     454          42 :         if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u) {
     455          36 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "test");
     456          36 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "test");
     457             :                 /* test for invalid stream due to truncation*/
     458          36 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "01234567890");
     459          36 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "01234567890");
     460             : #ifdef ENABLE_DEVELOPING
     461             :                 check_truncation = 1;
     462             :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "012345678901234567890");
     463             :                 check_truncation = 1;
     464             :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "012345678901234567890");
     465             : #endif
     466          36 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "\xa3h\xf9 -> 0xA3006800f900");
     467          36 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "\xa3h\xf9 -> 0xA3006800f900");
     468          36 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "0xA3006800f900 -> \xa3h\xf9");
     469          36 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "0xA3006800f900 -> \xa3h\xf9");
     470             : 
     471          36 :                 TestInput(SQL_C_LONG, "INT", SQL_WVARCHAR, "NVARCHAR(100)", "45236");
     472          36 :                 TestInput(SQL_C_LONG, "INT", SQL_WLONGVARCHAR, "NTEXT", "45236");
     473             : 
     474          36 :                 precision = 6;
     475          36 :                 TestOutput("NVARCHAR(20)", "foo test", SQL_C_CHAR, SQL_WVARCHAR, "6 foo te");
     476          36 :                 precision = 12;
     477          36 :                 TestOutput("NVARCHAR(20)", "foo test", SQL_C_CHAR, SQL_WVARCHAR, "8 foo test");
     478             :                 /* TODO use collate in syntax if available */
     479          36 :                 TestOutput("NVARCHAR(20)", "0xf800f900", SQL_C_CHAR, SQL_WVARCHAR, "2 \xf8\xf9");
     480             : 
     481          36 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WVARCHAR, "NVARCHAR(10)", "1EasyTest2");
     482          36 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WLONGVARCHAR, "NTEXT", "1EasyTest2");
     483          36 :                 use_nts = 1;
     484          36 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WVARCHAR, "NVARCHAR(10)", "1EasyTest3");
     485          36 :                 use_nts = 1;
     486          36 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WLONGVARCHAR, "NTEXT", "1EasyTest3");
     487          36 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(3)", SQL_WVARCHAR, "NVARCHAR(3)", "0xf800a300bc06");
     488          36 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(3)", SQL_WLONGVARCHAR, "NTEXT", "0xf800a300bc06");
     489             : 
     490          36 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_INTEGER, "INT", " -423785  -> -423785");
     491             : 
     492          36 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
     493          36 :                 TestInput(SQL_C_CHAR, "NTEXT COLLATE Latin1_General_CI_AS", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
     494             : 
     495          36 :                 TestInput(SQL_C_BINARY, "VARBINARY(100)", SQL_WVARCHAR, "NVARCHAR(20)", "0x4100450054004F00 -> AETO");
     496          36 :                 TestInput(SQL_C_BINARY, "IMAGE", SQL_WVARCHAR, "NVARCHAR(20)", "0x4100450054004F00 -> AETO");
     497             :         }
     498             :         /* MSSQL 2005 */
     499          42 :         if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x09000000u) {
     500          24 :                 TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_LONGVARCHAR, "VARCHAR(MAX)", "1EasyTest");
     501          24 :                 TestInput(SQL_C_BINARY, "VARBINARY(20)", SQL_LONGVARBINARY, "VARBINARY(MAX)", "Anything will suite!");
     502          24 :                 TestInput(SQL_C_CHAR, "MONEY", SQL_VARCHAR, "MONEY", "123.3456");
     503             :         }
     504             :         /* MSSQL 2008 */
     505          42 :         if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x0a000000u) {
     506          12 :                 TestInput(SQL_C_TYPE_DATE, "DATE", SQL_TYPE_DATE, "DATE", "2005-07-22");
     507          12 :                 TestInput(SQL_C_TYPE_TIME, "TIME", SQL_TYPE_TIME, "TIME", "13:02:03");
     508             :         }
     509             : 
     510             :         /* Sybase */
     511          42 :         if (!odbc_db_is_microsoft()) {
     512           6 :                 TestInput(SQL_C_CHAR, "UNIVARCHAR(100)", SQL_WCHAR, "UNIVARCHAR(100)", "test");
     513           6 :                 TestInput(SQL_C_WCHAR, "UNIVARCHAR(100)", SQL_WCHAR, "UNIVARCHAR(100)", "test");
     514           6 :                 TestInput(SQL_C_CHAR, "UNIVARCHAR(100)", SQL_WVARCHAR, "UNIVARCHAR(100)", "test");
     515           6 :                 TestInput(SQL_C_WCHAR, "UNIVARCHAR(100)", SQL_WVARCHAR, "UNIVARCHAR(100)", "test");
     516             :         }
     517          42 : }
     518             : 
     519             : int
     520           8 : main(int argc, char *argv[])
     521             : {
     522           8 :         odbc_use_version3 = 1;
     523           8 :         odbc_conn_additional_params = "ClientCharset=ISO-8859-1;";
     524             : 
     525           8 :         odbc_connect();
     526             : 
     527           8 :         if (((char *) &big_endian)[0] == 1)
     528           8 :                 big_endian = 0;
     529             : 
     530          22 :         for (use_cursors = 0; use_cursors <= 1; ++use_cursors) {
     531          16 :                 if (use_cursors) {
     532           8 :                         if (!tds_no_dm || !odbc_driver_is_freetds())
     533           0 :                                 odbc_reset_statement();
     534             :                         /* if connection does not support cursors returns success */
     535           8 :                         setenv("TDS_SKIP_SUCCESS", "1", 1);
     536           8 :                         odbc_check_cursor();
     537             :                 }
     538             : 
     539          14 :                 exec_direct = 1;
     540          14 :                 AllTests();
     541             : 
     542          14 :                 exec_direct = 0;
     543          14 :                 prepare_before = 1;
     544          14 :                 AllTests();
     545             : 
     546          14 :                 prepare_before = 0;
     547          14 :                 AllTests();
     548             :         }
     549             : 
     550           6 :         odbc_disconnect();
     551             : 
     552           6 :         printf("Done successfully!\n");
     553             :         return 0;
     554             : }
     555             : 

Generated by: LCOV version 1.13