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, ¶m_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 : int y, m, d;
318 :
319 54 : printf("use_cursors %d exec_direct %d prepare_before %d\n", use_cursors, exec_direct, prepare_before);
320 :
321 : /* test some NULLs */
322 54 : NullInput(SQL_C_CHAR, SQL_VARCHAR, "VARCHAR(100)");
323 54 : NullInput(SQL_C_CHAR, SQL_LONGVARCHAR, "TEXT");
324 54 : NullInput(SQL_C_LONG, SQL_INTEGER, "INTEGER");
325 54 : NullInput(SQL_C_LONG, SQL_LONGVARCHAR, "TEXT");
326 54 : NullInput(SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, "DATETIME");
327 54 : NullInput(SQL_C_FLOAT, SQL_REAL, "FLOAT");
328 54 : NullInput(SQL_C_NUMERIC, SQL_LONGVARCHAR, "TEXT");
329 54 : if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u)
330 48 : NullInput(SQL_C_BIT, SQL_BIT, "BIT");
331 54 : NullInput(SQL_C_DOUBLE, SQL_DOUBLE, "MONEY");
332 :
333 : /* FIXME why should return 38 0 as precision and scale ?? correct ?? */
334 54 : precision = 18;
335 54 : TestOutput("NUMERIC(18,2)", "123", SQL_C_NUMERIC, SQL_NUMERIC, "18 0 1 7B");
336 54 : TestOutput("DECIMAL(18,2)", "123", SQL_C_NUMERIC, SQL_DECIMAL, "18 0 1 7B");
337 54 : precision = 38;
338 54 : TestOutput("NUMERIC(18,2)", "123", SQL_C_NUMERIC, SQL_NUMERIC, "38 0 1 7B");
339 54 : TestInput(SQL_C_LONG, "INTEGER", SQL_VARCHAR, "VARCHAR(20)", "12345");
340 54 : TestInput(SQL_C_LONG, "INTEGER", SQL_LONGVARCHAR, "TEXT", "12345");
341 : /*
342 : * MS driver behavior for output parameters is different
343 : * former returns "313233" while newer "333133323333"
344 : */
345 54 : if (odbc_driver_is_freetds())
346 54 : TestOutput("VARCHAR(20)", "313233", SQL_C_BINARY, SQL_VARCHAR, "333133323333");
347 :
348 54 : only_test = 1;
349 54 : precision = 3;
350 54 : if (TestOutput("DATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ssssssl", 2004, 2, 24, 15, 16, 17, 0))) {
351 : /* FIXME our driver ignore precision for date */
352 30 : precision = 3;
353 : /* Some MS driver incorrectly prepare with smalldatetime*/
354 30 : if (!use_cursors || odbc_driver_is_freetds()) {
355 30 : TestOutput("DATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ll", 0x9497, 0xFBAA2C));
356 : }
357 30 : TestOutput("SMALLDATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ll", 0x9497, 0xFB9640));
358 : } else {
359 24 : TestOutput("SMALLDATETIME", "2004-02-24 15:16:17", SQL_C_BINARY, SQL_TIMESTAMP, pack("ssssssl", 2004, 2, 24, 15, 16, 0, 0));
360 : }
361 54 : TestInput(SQL_C_TYPE_TIMESTAMP, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 09:51:34");
362 :
363 : /* test timestamp millisecond round off */
364 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");
365 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");
366 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");
367 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");
368 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");
369 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");
370 :
371 : /* FIXME on ms driver first SQLFetch return SUCCESS_WITH_INFO for truncation error */
372 54 : TestInput(SQL_C_TYPE_DATE, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", "2005-07-22 13:02:03 -> 2005-07-22 00:00:00");
373 :
374 : /* Supplying a TIME to a TIMESTAMP input parameter should fill in the date with current client date */
375 54 : time(&curr_time);
376 54 : ltime = localtime(&curr_time);
377 54 : y = ltime->tm_year + 1900;
378 54 : m = ltime->tm_mon + 1;
379 54 : d = ltime->tm_mday;
380 54 : sprintf(buf, "2003-07-22 13:02:03 -> %04d-%02d-%02d 13:02:03", y, m, d);
381 54 : TestInput(SQL_C_TYPE_TIME, "DATETIME", SQL_TYPE_TIMESTAMP, "DATETIME", buf);
382 :
383 54 : TestInput(SQL_C_FLOAT, "FLOAT", SQL_REAL, "FLOAT", "1234.25");
384 54 : TestInput(SQL_C_DOUBLE, "REAL", SQL_REAL, "FLOAT", "-1234.25");
385 54 : TestInput(SQL_C_FLOAT, "REAL", SQL_REAL, "FLOAT", "1234.25");
386 54 : TestInput(SQL_C_DOUBLE, "FLOAT", SQL_REAL, "FLOAT", "-1234.25");
387 54 : TestInput(SQL_C_FLOAT, "FLOAT", SQL_FLOAT, "FLOAT", "1234.25");
388 54 : TestInput(SQL_C_DOUBLE, "REAL", SQL_FLOAT, "FLOAT", "-1234.25");
389 54 : TestInput(SQL_C_FLOAT, "FLOAT", SQL_DOUBLE, "FLOAT", "1234.25");
390 54 : TestInput(SQL_C_DOUBLE, "REAL", SQL_DOUBLE, "FLOAT", "-1234.25");
391 :
392 54 : TestInput(SQL_C_UTINYINT, "TINYINT", SQL_TINYINT, "TINYINT", "231");
393 54 : TestInput(SQL_C_STINYINT, "SMALLINT", SQL_SMALLINT, "SMALLINT", "-123");
394 :
395 54 : TestInput(SQL_C_NUMERIC, "NUMERIC(20,3)", SQL_NUMERIC, "NUMERIC(20,3)", "765432.2 -> 765432");
396 54 : TestInput(SQL_C_NUMERIC, "NUMERIC(20,3)", SQL_VARCHAR, "VARCHAR(20)", "578246.234 -> 578246");
397 54 : TestInput(SQL_C_NUMERIC, "NUMERIC(20,3)", SQL_LONGVARCHAR, "TEXT", "578246.234 -> 578246");
398 :
399 54 : TestInput(SQL_C_CHAR, "VARCHAR(100)", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
400 54 : TestInput(SQL_C_CHAR, "TEXT COLLATE Latin1_General_CI_AS", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
401 54 : TestInput(SQL_C_CHAR, "VARCHAR(100)", SQL_LONGVARBINARY, "IMAGE", "4145544F -> AETO");
402 54 : TestInput(SQL_C_BINARY, "VARBINARY(100)", SQL_VARCHAR, "VARCHAR(20)", "0x4145544F -> AETO");
403 54 : TestInput(SQL_C_BINARY, "IMAGE", SQL_VARCHAR, "VARCHAR(20)", "0x4145544F -> AETO");
404 :
405 54 : TestInput(SQL_C_BIT, "BIT", SQL_BIT, "BIT", "0");
406 54 : TestInput(SQL_C_BIT, "BIT", SQL_BIT, "BIT", "1");
407 :
408 54 : TestInput(SQL_C_DOUBLE, "MONEY", SQL_DOUBLE, "MONEY", "123.34");
409 :
410 54 : TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_VARCHAR, "VARCHAR(20)", "1EasyTest");
411 54 : TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_LONGVARCHAR, "TEXT", "1EasyTest");
412 54 : TestInput(SQL_C_WCHAR, "VARCHAR(10)", SQL_VARCHAR, "VARCHAR(10)", "Test 12345");
413 54 : TestInput(SQL_C_WCHAR, "VARCHAR(10)", SQL_LONGVARCHAR, "TEXT", "Test 12345");
414 : /* TODO use collate in syntax if available */
415 54 : TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_VARCHAR, "VARCHAR(20)", "me\xf4");
416 54 : TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_LONGVARCHAR, "TEXT", "me\xf4");
417 :
418 54 : precision = 6;
419 : /* output from char with conversions */
420 54 : TestOutput("VARCHAR(20)", "foo test", SQL_C_CHAR, SQL_VARCHAR, "6 foo te");
421 : /* TODO use collate in syntax if available */
422 : /* while usually on Microsoft database this encoding is valid on Sybase the database
423 : * could use UTF-8 encoding where \xf8\xf9 is an invalid encoded string */
424 54 : if (odbc_db_is_microsoft() && odbc_tds_version() > 0x700)
425 48 : TestOutput("VARCHAR(20) COLLATE Latin1_General_CI_AS", "NCHAR(0xf8) + NCHAR(0xf9)", SQL_C_CHAR, SQL_VARCHAR, "2 \xf8\xf9");
426 :
427 : /* MSSQL 2000 using ptotocol 7.1+ */
428 54 : if ((odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u && odbc_tds_version() > 0x700)
429 6 : || (!odbc_db_is_microsoft() && strncmp(odbc_db_version(), "15.00.", 6) >= 0)) {
430 54 : TestOutput("BIGINT", "-987654321065432", SQL_C_BINARY, SQL_BIGINT, big_endian ? "FFFC7DBBCF083228" : "283208CFBB7DFCFF");
431 54 : TestInput(SQL_C_SBIGINT, "BIGINT", SQL_BIGINT, "BIGINT", "-12345678901234");
432 : }
433 : /* MSSQL 2000 */
434 54 : if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u) {
435 48 : TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "test");
436 48 : TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "test");
437 : /* test for invalid stream due to truncation*/
438 48 : TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "01234567890");
439 48 : TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "01234567890");
440 : #ifdef ENABLE_DEVELOPING
441 : check_truncation = 1;
442 : TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "012345678901234567890");
443 : check_truncation = 1;
444 : TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "012345678901234567890");
445 : #endif
446 48 : TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "\xa3h\xf9 -> 0xA3006800f900");
447 48 : TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "\xa3h\xf9 -> 0xA3006800f900");
448 48 : TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WCHAR, "NVARCHAR(100)", "0xA3006800f900 -> \xa3h\xf9");
449 48 : TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_WLONGVARCHAR, "NTEXT", "0xA3006800f900 -> \xa3h\xf9");
450 :
451 48 : TestInput(SQL_C_LONG, "INT", SQL_WVARCHAR, "NVARCHAR(100)", "45236");
452 48 : TestInput(SQL_C_LONG, "INT", SQL_WLONGVARCHAR, "NTEXT", "45236");
453 :
454 48 : precision = 6;
455 48 : TestOutput("NVARCHAR(20)", "foo test", SQL_C_CHAR, SQL_WVARCHAR, "6 foo te");
456 48 : precision = 12;
457 48 : TestOutput("NVARCHAR(20)", "foo test", SQL_C_CHAR, SQL_WVARCHAR, "8 foo test");
458 : /* TODO use collate in syntax if available */
459 48 : TestOutput("NVARCHAR(20)", "0xf800f900", SQL_C_CHAR, SQL_WVARCHAR, "2 \xf8\xf9");
460 :
461 48 : TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WVARCHAR, "NVARCHAR(10)", "1EasyTest2");
462 48 : TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WLONGVARCHAR, "NTEXT", "1EasyTest2");
463 48 : use_nts = 1;
464 48 : TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WVARCHAR, "NVARCHAR(10)", "1EasyTest3");
465 48 : use_nts = 1;
466 48 : TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_WLONGVARCHAR, "NTEXT", "1EasyTest3");
467 48 : TestInput(SQL_C_WCHAR, "NVARCHAR(3)", SQL_WVARCHAR, "NVARCHAR(3)", "0xf800a300bc06");
468 48 : TestInput(SQL_C_WCHAR, "NVARCHAR(3)", SQL_WLONGVARCHAR, "NTEXT", "0xf800a300bc06");
469 :
470 48 : TestInput(SQL_C_WCHAR, "NVARCHAR(10)", SQL_INTEGER, "INT", " -423785 -> -423785");
471 :
472 48 : TestInput(SQL_C_CHAR, "NVARCHAR(100)", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
473 48 : TestInput(SQL_C_CHAR, "NTEXT COLLATE Latin1_General_CI_AS", SQL_VARBINARY, "VARBINARY(20)", "4145544F -> AETO");
474 :
475 48 : TestInput(SQL_C_BINARY, "VARBINARY(100)", SQL_WVARCHAR, "NVARCHAR(20)", "0x4100450054004F00 -> AETO");
476 48 : TestInput(SQL_C_BINARY, "IMAGE", SQL_WVARCHAR, "NVARCHAR(20)", "0x4100450054004F00 -> AETO");
477 : }
478 : /* MSSQL 2005 */
479 54 : if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x09000000u) {
480 36 : TestInput(SQL_C_CHAR, "VARCHAR(20)", SQL_LONGVARCHAR, "VARCHAR(MAX)", "1EasyTest");
481 36 : TestInput(SQL_C_BINARY, "VARBINARY(20)", SQL_LONGVARBINARY, "VARBINARY(MAX)", "Anything will suite!");
482 36 : TestInput(SQL_C_CHAR, "MONEY", SQL_VARCHAR, "MONEY", "123.3456");
483 : }
484 : /* MSSQL 2008 */
485 54 : if (odbc_db_is_microsoft() && odbc_db_version_int() >= 0x0a000000u) {
486 24 : TestInput(SQL_C_TYPE_DATE, "DATE", SQL_TYPE_DATE, "DATE", "2005-07-22");
487 24 : TestInput(SQL_C_TYPE_TIME, "TIME", SQL_TYPE_TIME, "TIME", "13:02:03");
488 : }
489 :
490 : /* Sybase */
491 54 : if (!odbc_db_is_microsoft()) {
492 6 : TestInput(SQL_C_CHAR, "UNIVARCHAR(100)", SQL_WCHAR, "UNIVARCHAR(100)", "test");
493 6 : TestInput(SQL_C_WCHAR, "UNIVARCHAR(100)", SQL_WCHAR, "UNIVARCHAR(100)", "test");
494 6 : TestInput(SQL_C_CHAR, "UNIVARCHAR(100)", SQL_WVARCHAR, "UNIVARCHAR(100)", "test");
495 6 : TestInput(SQL_C_WCHAR, "UNIVARCHAR(100)", SQL_WVARCHAR, "UNIVARCHAR(100)", "test");
496 : }
497 54 : }
498 :
499 10 : TEST_MAIN()
500 : {
501 10 : odbc_use_version3 = true;
502 10 : odbc_conn_additional_params = "ClientCharset=ISO-8859-1;";
503 :
504 10 : odbc_connect();
505 :
506 10 : if (((char *) &big_endian)[0] == 1)
507 10 : big_endian = 0;
508 :
509 28 : for (use_cursors = 0; use_cursors <= 1; ++use_cursors) {
510 20 : if (use_cursors) {
511 10 : if (!tds_no_dm || !odbc_driver_is_freetds())
512 0 : odbc_reset_statement();
513 : /* if connection does not support cursors returns success */
514 10 : setenv("TDS_SKIP_SUCCESS", "1", 1);
515 10 : odbc_check_cursor();
516 : }
517 :
518 18 : exec_direct = 1;
519 18 : AllTests();
520 :
521 18 : exec_direct = 0;
522 18 : prepare_before = 1;
523 18 : AllTests();
524 :
525 18 : prepare_before = 0;
526 18 : AllTests();
527 : }
528 :
529 8 : odbc_disconnect();
530 :
531 8 : printf("Done successfully!\n");
532 8 : return 0;
533 : }
534 :
|