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

Generated by: LCOV version 1.13