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, ¶m_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 :
|