LCOV - code coverage report
Current view: top level - src/odbc/unittests - genparams.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 303 310 97.7 %
Date: 2025-02-21 09:36:06 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        7242 : split_collate(ODBC_BUF** buf, const char **type)
      35             : {
      36        7242 :         const char *collate = "", *p;
      37             : 
      38        7242 :         if ((p = strstr(*type, " COLLATE ")) != NULL) {
      39         150 :                 if (odbc_db_is_microsoft())
      40         144 :                         collate = p;
      41         150 :                 *type = odbc_buf_asprintf(buf, "%.*s", (int) (p - *type), *type);
      42             :         }
      43        7242 :         return collate;
      44             : }
      45             : 
      46             : static int
      47         654 : 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         654 :         SQLLEN out_len = 0;
      52             :         const char *sep;
      53             :         const char *collate;
      54             : 
      55         654 :         odbc_reset_statement();
      56             : 
      57             :         /* build store procedure to test */
      58         654 :         odbc_command("IF OBJECT_ID('spTestProc') IS NOT NULL DROP PROC spTestProc");
      59         654 :         sep = "'";
      60         654 :         if (strncmp(value_to_convert, "0x", 2) == 0 || strncmp(value_to_convert, "NCHAR(", 6) == 0)
      61          96 :                 sep = "";
      62         654 :         collate = split_collate(&odbc_buf, &type);
      63         654 :         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         654 :         odbc_command(sbuf);
      66         654 :         memset(out_buf, 0, sizeof(out_buf));
      67             : 
      68         654 :         if (use_cursors) {
      69         300 :                 odbc_reset_statement();
      70         300 :                 CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S");
      71         300 :                 CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S");
      72             :         }
      73             : 
      74             :         /* bind parameter */
      75         654 :         if (exec_direct) {
      76         218 :                 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         218 :                 CHKExecDirect(T("{call spTestProc(?)}"), SQL_NTS, "S");
      81             :         } else {
      82         436 :                 if (prepare_before)
      83         218 :                         CHKPrepare(T("{call spTestProc(?)}"), SQL_NTS, "S");
      84             : 
      85         436 :                 CHKBindParameter(1, SQL_PARAM_OUTPUT, out_c_type, out_sql_type, precision, 0, out_buf,
      86             :                              sizeof(out_buf), &out_len, "S");
      87             : 
      88         436 :                 if (!prepare_before)
      89         218 :                         CHKPrepare(T("{call spTestProc(?)}"), SQL_NTS, "S");
      90             : 
      91         436 :                 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         654 :         if (use_cursors && !odbc_driver_is_freetds())
      99           0 :                 SQLMoreResults(odbc_stmt);
     100             : 
     101             :         /* test results */
     102         654 :         odbc_c2string(sbuf, out_c_type, out_buf, out_len);
     103             : 
     104         654 :         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         624 :         only_test = 0;
     114         624 :         odbc_command("drop proc spTestProc");
     115         624 :         ODBC_FREE();
     116         624 :         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        3294 : 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        3294 :         SQLLEN out_len = 0;
     137        3294 :         const char *expected = value_to_convert;
     138        3294 :         size_t value_len = strlen(value_to_convert);
     139             :         const char *p;
     140        3294 :         const char *sep = "'";
     141             :         const char *collate;
     142             : 
     143        3294 :         odbc_reset_statement();
     144             : 
     145             :         /* execute a select to get data as wire */
     146        3294 :         if ((p = strstr(value_to_convert, " -> ")) != NULL) {
     147        1296 :                 value_len = p - value_to_convert;
     148        1296 :                 expected = p + 4;
     149             :         }
     150        3294 :         if (value_len >= 2 && strncmp(value_to_convert, "0x", 2) == 0)
     151         396 :                 sep = "";
     152        3294 :         collate = split_collate(&odbc_buf, &type);
     153        3294 :         sprintf(sbuf, "SELECT CONVERT(%s, %s%.*s%s%s)", type, sep, (int) value_len, value_to_convert, sep, collate);
     154        3294 :         odbc_command(sbuf);
     155        3294 :         SQLBindCol(odbc_stmt, 1, out_c_type, out_buf, sizeof(out_buf), &out_len);
     156        3294 :         CHKFetch("SI");
     157        3294 :         CHKFetch("No");
     158        3294 :         CHKMoreResults("No");
     159        3294 :         if (use_nts) {
     160          96 :                 out_len = SQL_NTS;
     161          96 :                 use_nts = 0;
     162             :         }
     163             : 
     164             :         /* create a table with a column of that type */
     165        3294 :         odbc_reset_statement();
     166        3294 :         collate = split_collate(&odbc_buf, &param_type);
     167        3294 :         sprintf(sbuf, "CREATE TABLE #tmp_insert (col %s%s)", param_type, collate);
     168        3294 :         odbc_command(sbuf);
     169             : 
     170        3294 :         if (use_cursors) {
     171        1518 :                 odbc_reset_statement();
     172        1518 :                 CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S");
     173        1518 :                 CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S");
     174             :         }
     175             : 
     176             :         /* insert data using prepared statements */
     177        3294 :         sprintf(sbuf, "INSERT INTO #tmp_insert VALUES(?)");
     178        3294 :         if (exec_direct) {
     179        1098 :                 CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, out_buf, sizeof(out_buf), &out_len, "S");
     180             : 
     181        1098 :                 if (check_truncation)
     182           0 :                         CHKExecDirect(T(sbuf), SQL_NTS, "E");
     183             :                 else
     184        1098 :                         CHKExecDirect(T(sbuf), SQL_NTS, "SNo");
     185             :         } else {
     186        2196 :                 if (prepare_before)
     187        1098 :                         CHKPrepare(T(sbuf), SQL_NTS, "S");
     188             : 
     189        2196 :                 CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, out_buf, sizeof(out_buf), &out_len, "S");
     190             : 
     191        2196 :                 if (!prepare_before)
     192        1098 :                         CHKPrepare(T(sbuf), SQL_NTS, "S");
     193             : 
     194        2196 :                 if (check_truncation)
     195           0 :                         CHKExecute("E");
     196             :                 else
     197        2196 :                         CHKExecute("SNo");
     198             :         }
     199             : 
     200             :         /* check if row is present */
     201        3294 :         if (!check_truncation) {
     202             :                 char *p;
     203             : 
     204        3294 :                 odbc_reset_statement();
     205        3294 :                 sep = "'";
     206        3294 :                 if (strncmp(expected, "0x", 2) == 0)
     207         192 :                         sep = "";
     208             : 
     209        3294 :                 strcpy(sbuf, "SELECT * FROM #tmp_insert WHERE ");
     210        3294 :                 p = strchr(sbuf, 0);
     211        3294 :                 if (strcmp(param_type, "TEXT") == 0)
     212         270 :                         sprintf(p, "CONVERT(VARCHAR(255), col) = CONVERT(VARCHAR(255), %s%s%s)", sep, expected, sep);
     213        3024 :                 else if (strcmp(param_type, "NTEXT") == 0)
     214         384 :                         sprintf(p, "CONVERT(NVARCHAR(2000), col) = CONVERT(NVARCHAR(2000), %s%s%s)", sep, expected, sep);
     215        2640 :                 else if (strcmp(param_type, "IMAGE") == 0)
     216          54 :                         sprintf(p, "CONVERT(VARBINARY(255), col) = CONVERT(VARBINARY(255), %s%s%s)", sep, expected, sep);
     217             :                 else
     218        2586 :                         sprintf(p, "col = CONVERT(%s, %s%s%s)", param_type, sep, expected, sep);
     219        3294 :                 odbc_command(sbuf);
     220             : 
     221        3294 :                 CHKFetch("S");
     222        3294 :                 CHKFetch("No");
     223        3294 :                 CHKMoreResults("No");
     224             :         }
     225        3294 :         check_truncation = 0;
     226        3294 :         odbc_command("DROP TABLE #tmp_insert");
     227        3294 :         ODBC_FREE();
     228        3294 : }
     229             : 
     230             : /* stripped down version of TestInput for NULLs */
     231             : static void
     232         480 : NullInput(SQLSMALLINT out_c_type, SQLSMALLINT out_sql_type, const char *param_type)
     233             : {
     234             :         char sbuf[1024];
     235         480 :         SQLLEN out_len = SQL_NULL_DATA;
     236             : 
     237         480 :         odbc_reset_statement();
     238             : 
     239             :         /* create a table with a column of that type */
     240         480 :         odbc_reset_statement();
     241         480 :         sprintf(sbuf, "CREATE TABLE #tmp_insert (col %s NULL)", param_type);
     242         480 :         odbc_command(sbuf);
     243             : 
     244         480 :         if (use_cursors) {
     245         216 :                 odbc_reset_statement();
     246         216 :                 CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S");
     247         216 :                 CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S");
     248             :         }
     249             : 
     250             :         /* insert data using prepared statements */
     251         480 :         sprintf(sbuf, "INSERT INTO #tmp_insert VALUES(?)");
     252         480 :         if (exec_direct) {
     253         160 :                 CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, NULL, 1, &out_len, "S");
     254             : 
     255         160 :                 CHKExecDirect(T(sbuf), SQL_NTS, "SNo");
     256             :         } else {
     257         320 :                 if (prepare_before)
     258         160 :                         CHKPrepare(T(sbuf), SQL_NTS, "S");
     259             : 
     260         320 :                 CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, NULL, 1, &out_len, "S");
     261             : 
     262         320 :                 if (!prepare_before)
     263         160 :                         CHKPrepare(T(sbuf), SQL_NTS, "S");
     264             : 
     265         320 :                 CHKExecute("SNo");
     266             :         }
     267             : 
     268             :         /* check if row is present */
     269         480 :         odbc_reset_statement();
     270         480 :         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         462 :                 odbc_command("SELECT * FROM #tmp_insert WHERE col IS NULL");
     274             : 
     275         480 :         CHKFetch("S");
     276         480 :         CHKFetch("No");
     277         480 :         CHKMoreResults("No");
     278         480 :         odbc_command("DROP TABLE #tmp_insert");
     279         480 :         ODBC_FREE();
     280         480 : }
     281             : 
     282             : 
     283             : static int big_endian = 1;
     284             : 
     285             : static const char*
     286         138 : pack(const char *fmt, ...)
     287             : {
     288             :         static char out[80];
     289         138 :         char *p = out;
     290             : 
     291             :         va_list v;
     292         138 :         va_start(v, fmt);
     293         804 :         for (; *fmt; ++fmt) {
     294         666 :                 unsigned n = va_arg(v, unsigned);
     295         666 :                 int i, l = 2;
     296             : 
     297         666 :                 assert(p - out + 8 < sizeof(out));
     298         666 :                 switch (*fmt) {
     299         198 :                 case 'l':
     300         198 :                         l += 2;
     301         666 :                 case 's':
     302        2394 :                         for (i = 0; i < l; ++i) {
     303        1728 :                                 sprintf(p, "%02X", (n >> (8*(big_endian ? l-1-i : i))) & 0xffu);
     304        1728 :                                 p += 2;
     305             :                         }
     306             :                         break;
     307             :                 default:
     308           0 :                         assert(0);
     309             :                 }
     310             :         }
     311         138 :         *p = 0;
     312         138 :         va_end(v);
     313         138 :         return out;
     314             : }
     315             : 
     316             : static void
     317          54 : 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          54 :         printf("use_cursors %d exec_direct %d prepare_before %d\n", use_cursors, exec_direct, prepare_before);
     327             : 
     328             :         /* test some NULLs */
     329          54 :         NullInput(SQL_C_CHAR, SQL_VARCHAR, "VARCHAR(100)");
     330          54 :         NullInput(SQL_C_CHAR, SQL_LONGVARCHAR, "TEXT");
     331          54 :         NullInput(SQL_C_LONG, SQL_INTEGER, "INTEGER");
     332          54 :         NullInput(SQL_C_LONG, SQL_LONGVARCHAR, "TEXT");
     333          54 :         NullInput(SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, "DATETIME");
     334          54 :         NullInput(SQL_C_FLOAT,  SQL_REAL, "FLOAT");
     335          54 :         NullInput(SQL_C_NUMERIC, SQL_LONGVARCHAR, "TEXT");
     336          54 :         if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u)
     337          48 :                 NullInput(SQL_C_BIT, SQL_BIT, "BIT");
     338          54 :         NullInput(SQL_C_DOUBLE, SQL_DOUBLE, "MONEY");
     339             : 
     340             :         /* FIXME why should return 38 0 as precision and scale ?? correct ?? */
     341          54 :         precision = 18;
     342          54 :         TestOutput("NUMERIC(18,2)", "123", SQL_C_NUMERIC, SQL_NUMERIC, "18 0 1 7B");
     343          54 :         TestOutput("DECIMAL(18,2)", "123", SQL_C_NUMERIC, SQL_DECIMAL, "18 0 1 7B");
     344          54 :         precision = 38;
     345          54 :         TestOutput("NUMERIC(18,2)", "123", SQL_C_NUMERIC, SQL_NUMERIC, "38 0 1 7B");
     346          54 :         TestInput(SQL_C_LONG, "INTEGER", SQL_VARCHAR, "VARCHAR(20)", "12345");
     347          54 :         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          54 :         if (odbc_driver_is_freetds())
     353          54 :                 TestOutput("VARCHAR(20)", "313233", SQL_C_BINARY, SQL_VARCHAR, "333133323333");
     354             : 
     355          54 :         only_test = 1;
     356          54 :         precision = 3;
     357          54 :         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          24 :                 TestOutput("SMALLDATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ssssssl", 2004, 2, 24, 15, 16, 0, 0));
     367             :         }
     368          54 :         TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34");
     369             : 
     370             :         /* test timestamp millisecond round off */
     371          54 :         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          54 :         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          54 :         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          54 :         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          54 :         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          54 :         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          54 :         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          54 :         time(&curr_time);
     383          54 :         ltime = localtime(&curr_time);
     384          54 :         y = ltime->tm_year + 1900;
     385          54 :         m = ltime->tm_mon + 1;
     386          54 :         d = ltime->tm_mday;
     387             :         /* server concept of data can be different so try ask to server */
     388          54 :         odbc_command("SELECT GETDATE()");
     389          54 :         SQLBindCol(odbc_stmt, 1, SQL_C_CHAR, date, sizeof(date), NULL);
     390          54 :         if (SQLFetch(odbc_stmt) == SQL_SUCCESS) {
     391             :                 int a, b, c;
     392          54 :                 if (sscanf(date, "%d-%d-%d", &a, &b, &c) == 3) {
     393          54 :                         y = a;
     394          54 :                         m = b;
     395          54 :                         d = c;
     396             :                 }
     397             :         }
     398          54 :         SQLFetch(odbc_stmt);
     399          54 :         SQLMoreResults(odbc_stmt);
     400          54 :         SQLFreeStmt(odbc_stmt, SQL_UNBIND);
     401          54 :         sprintf(buf, "2003-07-22 13:02:03 -> %04d-%02d-%02d 13:02:03", (int) y, (int) m, (int) d);
     402          54 :         TestInput(SQL_C_TYPE_TIME, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", buf);
     403             : 
     404          54 :         TestInput(SQL_C_FLOAT,  "FLOAT", SQL_REAL, "FLOAT", "1234.25");
     405          54 :         TestInput(SQL_C_DOUBLE, "REAL", SQL_REAL, "FLOAT", "-1234.25");
     406          54 :         TestInput(SQL_C_FLOAT,  "REAL", SQL_REAL, "FLOAT", "1234.25");
     407          54 :         TestInput(SQL_C_DOUBLE, "FLOAT", SQL_REAL, "FLOAT", "-1234.25");
     408          54 :         TestInput(SQL_C_FLOAT,  "FLOAT", SQL_FLOAT, "FLOAT", "1234.25");
     409          54 :         TestInput(SQL_C_DOUBLE, "REAL", SQL_FLOAT, "FLOAT", "-1234.25");
     410          54 :         TestInput(SQL_C_FLOAT,  "FLOAT", SQL_DOUBLE, "FLOAT", "1234.25");
     411          54 :         TestInput(SQL_C_DOUBLE, "REAL", SQL_DOUBLE, "FLOAT", "-1234.25");
     412             : 
     413          54 :         TestInput(SQL_C_UTINYINT, "TINYINT", SQL_TINYINT, "TINYINT", "231");
     414          54 :         TestInput(SQL_C_STINYINT, "SMALLINT", SQL_SMALLINT, "SMALLINT", "-123");
     415             : 
     416          54 :         TestInput(SQL_C_NUMERIC, "NUMERIC(20,3)", SQL_NUMERIC, "NUMERIC(20,3)", "765432.2 -> 765432");
     417          54 :         TestInput(SQL_C_NUMERIC, "NUMERIC(20,3)", SQL_VARCHAR, "VARCHAR(20)", "578246.234 -> 578246");
     418          54 :         TestInput(SQL_C_NUMERIC, "NUMERIC(20,3)", SQL_LONGVARCHAR, "TEXT", "578246.234 -> 578246");
     419             : 
     420          54 :         TestInput(SQL_C_CHAR, "VARCHAR(100)", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
     421          54 :         TestInput(SQL_C_CHAR, "TEXT COLLATE Latin1_General_CI_AS", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
     422          54 :         TestInput(SQL_C_CHAR, "VARCHAR(100)", SQL_LONGVARBINARY, "IMAGE", "4145544F -> AETO");
     423          54 :         TestInput(SQL_C_BINARY, "VARBINARY(100)", SQL_VARCHAR, "VARCHAR(20)", "0x4145544F -> AETO");
     424          54 :         TestInput(SQL_C_BINARY, "IMAGE", SQL_VARCHAR, "VARCHAR(20)", "0x4145544F -> AETO");
     425             : 
     426          54 :         TestInput(SQL_C_BIT, "BIT", SQL_BIT, "BIT", "0");
     427          54 :         TestInput(SQL_C_BIT, "BIT", SQL_BIT, "BIT", "1");
     428             : 
     429          54 :         TestInput(SQL_C_DOUBLE, "MONEY", SQL_DOUBLE, "MONEY", "123.34");
     430             : 
     431          54 :         TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_VARCHAR, "VARCHAR(20)", "1EasyTest");
     432          54 :         TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_LONGVARCHAR, "TEXT", "1EasyTest");
     433          54 :         TestInput(SQL_C_WCHAR, "VARCHAR(10)", SQL_VARCHAR, "VARCHAR(10)", "Test 12345");
     434          54 :         TestInput(SQL_C_WCHAR, "VARCHAR(10)", SQL_LONGVARCHAR, "TEXT", "Test 12345");
     435             :         /* TODO use collate in syntax if available */
     436          54 :         TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_VARCHAR, "VARCHAR(20)", "me\xf4");
     437          54 :         TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_LONGVARCHAR, "TEXT", "me\xf4");
     438             : 
     439          54 :         precision = 6;
     440             :         /* output from char with conversions */
     441          54 :         TestOutput("VARCHAR(20)", "foo test", SQL_C_CHAR, SQL_VARCHAR, "6 foo te");
     442             :         /* TODO use collate in syntax if available */
     443             :         /* while usually on Microsoft database this encoding is valid on Sybase the database
     444             :          * could use UTF-8 encoding where \xf8\xf9 is an invalid encoded string */
     445          54 :         if (odbc_db_is_microsoft() && odbc_tds_version() > 0x700)
     446          48 :                 TestOutput("VARCHAR(20) COLLATE Latin1_General_CI_AS", "NCHAR(0xf8) + NCHAR(0xf9)", SQL_C_CHAR, SQL_VARCHAR, "2 \xf8\xf9");
     447             : 
     448             :         /* MSSQL 2000 using ptotocol 7.1+ */
     449          54 :         if ((odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u && odbc_tds_version() > 0x700)
     450           6 :             || (!odbc_db_is_microsoft() && strncmp(odbc_db_version(), "15.00.", 6) >= 0)) {
     451          54 :                 TestOutput("BIGINT", "-987654321065432", SQL_C_BINARY, SQL_BIGINT, big_endian ? "FFFC7DBBCF083228" : "283208CFBB7DFCFF");
     452          54 :                 TestInput(SQL_C_SBIGINT, "BIGINT", SQL_BIGINT, "BIGINT", "-12345678901234");
     453             :         }
     454             :         /* MSSQL 2000 */
     455          54 :         if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u) {
     456          48 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "test");
     457          48 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "test");
     458             :                 /* test for invalid stream due to truncation*/
     459          48 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "01234567890");
     460          48 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "01234567890");
     461             : #ifdef ENABLE_DEVELOPING
     462             :                 check_truncation = 1;
     463             :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "012345678901234567890");
     464             :                 check_truncation = 1;
     465             :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "012345678901234567890");
     466             : #endif
     467          48 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "\xa3h\xf9 -> 0xA3006800f900");
     468          48 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "\xa3h\xf9 -> 0xA3006800f900");
     469          48 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "0xA3006800f900 -> \xa3h\xf9");
     470          48 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "0xA3006800f900 -> \xa3h\xf9");
     471             : 
     472          48 :                 TestInput(SQL_C_LONG, "INT", SQL_WVARCHAR, "NVARCHAR(100)", "45236");
     473          48 :                 TestInput(SQL_C_LONG, "INT", SQL_WLONGVARCHAR, "NTEXT", "45236");
     474             : 
     475          48 :                 precision = 6;
     476          48 :                 TestOutput("NVARCHAR(20)", "foo test", SQL_C_CHAR, SQL_WVARCHAR, "6 foo te");
     477          48 :                 precision = 12;
     478          48 :                 TestOutput("NVARCHAR(20)", "foo test", SQL_C_CHAR, SQL_WVARCHAR, "8 foo test");
     479             :                 /* TODO use collate in syntax if available */
     480          48 :                 TestOutput("NVARCHAR(20)", "0xf800f900", SQL_C_CHAR, SQL_WVARCHAR, "2 \xf8\xf9");
     481             : 
     482          48 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WVARCHAR, "NVARCHAR(10)", "1EasyTest2");
     483          48 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WLONGVARCHAR, "NTEXT", "1EasyTest2");
     484          48 :                 use_nts = 1;
     485          48 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WVARCHAR, "NVARCHAR(10)", "1EasyTest3");
     486          48 :                 use_nts = 1;
     487          48 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WLONGVARCHAR, "NTEXT", "1EasyTest3");
     488          48 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(3)", SQL_WVARCHAR, "NVARCHAR(3)", "0xf800a300bc06");
     489          48 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(3)", SQL_WLONGVARCHAR, "NTEXT", "0xf800a300bc06");
     490             : 
     491          48 :                 TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_INTEGER, "INT", " -423785  -> -423785");
     492             : 
     493          48 :                 TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
     494          48 :                 TestInput(SQL_C_CHAR, "NTEXT COLLATE Latin1_General_CI_AS", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
     495             : 
     496          48 :                 TestInput(SQL_C_BINARY, "VARBINARY(100)", SQL_WVARCHAR, "NVARCHAR(20)", "0x4100450054004F00 -> AETO");
     497          48 :                 TestInput(SQL_C_BINARY, "IMAGE", SQL_WVARCHAR, "NVARCHAR(20)", "0x4100450054004F00 -> AETO");
     498             :         }
     499             :         /* MSSQL 2005 */
     500          54 :         if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x09000000u) {
     501          36 :                 TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_LONGVARCHAR, "VARCHAR(MAX)", "1EasyTest");
     502          36 :                 TestInput(SQL_C_BINARY, "VARBINARY(20)", SQL_LONGVARBINARY, "VARBINARY(MAX)", "Anything will suite!");
     503          36 :                 TestInput(SQL_C_CHAR, "MONEY", SQL_VARCHAR, "MONEY", "123.3456");
     504             :         }
     505             :         /* MSSQL 2008 */
     506          54 :         if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x0a000000u) {
     507          24 :                 TestInput(SQL_C_TYPE_DATE, "DATE", SQL_TYPE_DATE, "DATE", "2005-07-22");
     508          24 :                 TestInput(SQL_C_TYPE_TIME, "TIME", SQL_TYPE_TIME, "TIME", "13:02:03");
     509             :         }
     510             : 
     511             :         /* Sybase */
     512          54 :         if (!odbc_db_is_microsoft()) {
     513           6 :                 TestInput(SQL_C_CHAR, "UNIVARCHAR(100)", SQL_WCHAR, "UNIVARCHAR(100)", "test");
     514           6 :                 TestInput(SQL_C_WCHAR, "UNIVARCHAR(100)", SQL_WCHAR, "UNIVARCHAR(100)", "test");
     515           6 :                 TestInput(SQL_C_CHAR, "UNIVARCHAR(100)", SQL_WVARCHAR, "UNIVARCHAR(100)", "test");
     516           6 :                 TestInput(SQL_C_WCHAR, "UNIVARCHAR(100)", SQL_WVARCHAR, "UNIVARCHAR(100)", "test");
     517             :         }
     518          54 : }
     519             : 
     520             : int
     521          10 : main(void)
     522             : {
     523          10 :         odbc_use_version3 = 1;
     524          10 :         odbc_conn_additional_params = "ClientCharset=ISO-8859-1;";
     525             : 
     526          10 :         odbc_connect();
     527             : 
     528          10 :         if (((char *) &big_endian)[0] == 1)
     529          10 :                 big_endian = 0;
     530             : 
     531          28 :         for (use_cursors = 0; use_cursors <= 1; ++use_cursors) {
     532          20 :                 if (use_cursors) {
     533          10 :                         if (!tds_no_dm || !odbc_driver_is_freetds())
     534           0 :                                 odbc_reset_statement();
     535             :                         /* if connection does not support cursors returns success */
     536          10 :                         setenv("TDS_SKIP_SUCCESS", "1", 1);
     537          10 :                         odbc_check_cursor();
     538             :                 }
     539             : 
     540          18 :                 exec_direct = 1;
     541          18 :                 AllTests();
     542             : 
     543          18 :                 exec_direct = 0;
     544          18 :                 prepare_before = 1;
     545          18 :                 AllTests();
     546             : 
     547          18 :                 prepare_before = 0;
     548          18 :                 AllTests();
     549             :         }
     550             : 
     551           8 :         odbc_disconnect();
     552             : 
     553           8 :         printf("Done successfully!\n");
     554             :         return 0;
     555             : }
     556             : 

Generated by: LCOV version 1.13