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