Line data Source code
1 : /* Testing large objects */
2 : /* Test from Sebastien Flaesch */
3 :
4 : #include "common.h"
5 : #include <ctype.h>
6 : #include <assert.h>
7 :
8 : #define NBYTES 10000u
9 :
10 : static int failed = 0;
11 :
12 : static void
13 : fill_chars(char *buf, size_t len, unsigned int start, unsigned int step)
14 : {
15 : size_t n;
16 :
17 280028 : for (n = 0; n < len; ++n)
18 280000 : buf[n] = 'a' + ((start+n) * step % ('z' - 'a' + 1));
19 : }
20 :
21 : static void
22 112 : fill_hex(char *buf, size_t len, unsigned int start, unsigned int step)
23 : {
24 : size_t n;
25 :
26 1120112 : for (n = 0; n < len; ++n)
27 1120000 : sprintf(buf + 2*n, "%2x", (unsigned int)('a' + ((start+n) * step % ('z' - 'a' + 1))));
28 112 : }
29 :
30 :
31 : static int
32 : check_chars(const char *buf, size_t len, unsigned int start, unsigned int step)
33 : {
34 : size_t n;
35 :
36 1120336 : for (n = 0; n < len; ++n)
37 1120000 : if (buf[n] != 'a' + ((start+n) * step % ('z' - 'a' + 1)))
38 : return 0;
39 :
40 : return 1;
41 : }
42 :
43 : static int
44 896 : check_hex(const char *buf, size_t len, unsigned int start, unsigned int step)
45 : {
46 : size_t n;
47 : char symbol[3];
48 :
49 4480896 : for (n = 0; n < len; ++n) {
50 4480000 : sprintf(symbol, "%2x", (unsigned int)('a' + ((start+n) / 2 * step % ('z' - 'a' + 1))));
51 4480000 : if (tolower((unsigned char) buf[n]) != symbol[(start+n) % 2])
52 : return 0;
53 : }
54 :
55 : return 1;
56 : }
57 :
58 : #define MAX_TESTS 10
59 : typedef struct {
60 : unsigned num;
61 : SQLSMALLINT c_type, sql_type;
62 : const char *db_type;
63 : unsigned gen1, gen2;
64 : SQLLEN vind;
65 : char *buf;
66 : } test_info;
67 :
68 : static test_info test_infos[MAX_TESTS];
69 : static unsigned num_tests = 0;
70 :
71 : static void
72 0 : dump(FILE* out, const char* start, void* buf, unsigned len)
73 : {
74 : unsigned n;
75 : char s[17];
76 0 : if (len >= 16)
77 0 : len = 16;
78 0 : fprintf(out, "%s", start);
79 0 : for (n = 0; n < len; ++n) {
80 0 : unsigned char c = ((unsigned char*)buf)[n];
81 0 : fprintf(out, " %02X", c);
82 0 : s[n] = (c >= 0x20 && c < 127) ? (char) c : '.';
83 : }
84 0 : s[len] = 0;
85 0 : fprintf(out, " - %s\n", s);
86 0 : }
87 :
88 : static void
89 112 : readBlob(test_info *t)
90 : {
91 : SQLRETURN rc;
92 : char buf[4096];
93 112 : SQLLEN len, total = 0;
94 112 : int i = 0;
95 : int check;
96 :
97 112 : printf(">> readBlob field %d\n", t->num);
98 : while (1) {
99 784 : i++;
100 448 : rc = CHKGetData(t->num, SQL_C_BINARY, (SQLPOINTER) buf, (SQLINTEGER) sizeof(buf), &len, "SINo");
101 448 : if (rc == SQL_NO_DATA || len <= 0)
102 : break;
103 336 : if (len > (SQLLEN) sizeof(buf))
104 224 : len = (SQLLEN) sizeof(buf);
105 336 : printf(">> step %d: %d bytes readed\n", i, (int) len);
106 672 : check = check_chars(buf, len, t->gen1 + total, t->gen2);
107 336 : if (!check) {
108 0 : fprintf(stderr, "Wrong buffer content\n");
109 0 : dump(stderr, " buf ", buf, len);
110 0 : failed = 1;
111 : }
112 336 : total += len;
113 : }
114 112 : printf(">> total bytes read = %d \n", (int) total);
115 112 : if (total != 10000) {
116 0 : fprintf(stderr, "Wrong buffer length, expected 20000\n");
117 0 : failed = 1;
118 : }
119 112 : }
120 :
121 : static void
122 224 : readBlobAsChar(test_info *t, int step, int wide)
123 : {
124 224 : SQLRETURN rc = SQL_SUCCESS_WITH_INFO;
125 : char buf[8192];
126 224 : SQLLEN len, total = 0, len2;
127 224 : int i = 0;
128 : int check;
129 : int bufsize;
130 :
131 224 : SQLSMALLINT type = SQL_C_CHAR;
132 224 : unsigned int char_len = 1;
133 224 : if (wide) {
134 112 : char_len = sizeof(SQLWCHAR);
135 112 : type = SQL_C_WCHAR;
136 : }
137 :
138 224 : if (step%2) bufsize = sizeof(buf) - char_len;
139 : else bufsize = sizeof(buf);
140 :
141 224 : printf(">> readBlobAsChar field %d\n", t->num);
142 1344 : while (rc == SQL_SUCCESS_WITH_INFO) {
143 896 : i++;
144 896 : rc = CHKGetData(t->num, type, (SQLPOINTER) buf, (SQLINTEGER) bufsize, &len, "SINo");
145 896 : if (rc == SQL_SUCCESS_WITH_INFO && len == SQL_NO_TOTAL) {
146 224 : len = bufsize - char_len;
147 224 : rc = SQL_SUCCESS;
148 : }
149 672 : if (rc == SQL_NO_DATA || len <= 0)
150 : break;
151 896 : rc = CHKGetData(t->num, type, (SQLPOINTER) buf, 0, &len2, "SINo");
152 896 : if (rc == SQL_SUCCESS_WITH_INFO && len2 != SQL_NO_TOTAL)
153 448 : len = len - len2;
154 : #if 0
155 : if (len > (SQLLEN) (bufsize - char_len))
156 : len = (SQLLEN) (bufsize - char_len);
157 : len -= len % (2u * char_len);
158 : #endif
159 896 : printf(">> step %d: %d bytes readed\n", i, (int) len);
160 :
161 896 : if (wide) {
162 560 : len /= sizeof(SQLWCHAR);
163 560 : odbc_from_sqlwchar((char *) buf, (SQLWCHAR *) buf, len + 1);
164 : }
165 :
166 896 : check = check_hex(buf, len, 2*t->gen1 + total, t->gen2);
167 896 : if (!check) {
168 0 : fprintf(stderr, "Wrong buffer content\n");
169 0 : dump(stderr, " buf ", buf, len);
170 0 : failed = 1;
171 : }
172 896 : total += len;
173 : }
174 224 : printf(">> total bytes read = %d \n", (int) total);
175 224 : if (total != 20000) {
176 0 : fprintf(stderr, "Wrong buffer length, expected 20000\n");
177 0 : failed = 1;
178 : }
179 224 : }
180 :
181 : static void
182 84 : add_test(SQLSMALLINT c_type, SQLSMALLINT sql_type, const char *db_type, unsigned gen1, unsigned gen2)
183 : {
184 84 : test_info *t = NULL;
185 : size_t buf_len;
186 :
187 84 : if (num_tests >= MAX_TESTS) {
188 0 : fprintf(stderr, "too max tests\n");
189 0 : exit(1);
190 : }
191 :
192 84 : t = &test_infos[num_tests++];
193 84 : t->num = num_tests;
194 84 : t->c_type = c_type;
195 84 : t->sql_type = sql_type;
196 84 : t->db_type = db_type;
197 84 : t->gen1 = gen1;
198 84 : t->gen2 = gen2;
199 84 : t->vind = 0;
200 84 : switch (c_type) {
201 : case SQL_C_CHAR:
202 : buf_len = NBYTES*2+1;
203 : break;
204 28 : case SQL_C_WCHAR:
205 28 : buf_len = (NBYTES*2+1) * sizeof(SQLWCHAR);
206 28 : break;
207 28 : default:
208 28 : buf_len = NBYTES;
209 : }
210 84 : t->buf = (char*) malloc(buf_len);
211 84 : if (!t->buf) {
212 0 : fprintf(stderr, "memory error\n");
213 0 : exit(1);
214 : }
215 84 : if (c_type != SQL_C_CHAR && c_type != SQL_C_WCHAR)
216 28 : fill_chars(t->buf, NBYTES, t->gen1, t->gen2);
217 : else
218 56 : memset(t->buf, 0, buf_len);
219 84 : t->vind = SQL_LEN_DATA_AT_EXEC((SQLLEN) buf_len);
220 84 : }
221 :
222 : static void
223 10 : free_tests(void)
224 : {
225 104 : while (num_tests > 0) {
226 84 : test_info *t = &test_infos[--num_tests];
227 84 : free(t->buf);
228 84 : t->buf = NULL;
229 : }
230 10 : }
231 :
232 : int
233 10 : main(void)
234 : {
235 : SQLRETURN RetCode;
236 10 : SQLHSTMT old_odbc_stmt = SQL_NULL_HSTMT;
237 : int i;
238 :
239 : int key;
240 : SQLLEN vind0;
241 10 : int cnt = 2, wide;
242 : char sql[256];
243 10 : test_info *t = NULL;
244 :
245 10 : odbc_use_version3 = 1;
246 10 : odbc_connect();
247 :
248 : /* tests (W)CHAR/BINARY -> (W)CHAR/BINARY (9 cases) */
249 10 : add_test(SQL_C_BINARY, SQL_LONGVARCHAR, "TEXT", 123, 1 );
250 10 : add_test(SQL_C_BINARY, SQL_LONGVARBINARY, "IMAGE", 987, 25);
251 10 : add_test(SQL_C_CHAR, SQL_LONGVARBINARY, "IMAGE", 987, 25);
252 10 : add_test(SQL_C_CHAR, SQL_LONGVARCHAR, "TEXT", 343, 47);
253 10 : add_test(SQL_C_WCHAR, SQL_LONGVARBINARY, "IMAGE", 561, 29);
254 10 : add_test(SQL_C_WCHAR, SQL_LONGVARCHAR, "TEXT", 698, 24);
255 10 : if (odbc_db_is_microsoft()) {
256 8 : add_test(SQL_C_BINARY, SQL_WLONGVARCHAR, "NTEXT", 765, 12);
257 8 : add_test(SQL_C_CHAR, SQL_WLONGVARCHAR, "NTEXT", 237, 71);
258 8 : add_test(SQL_C_WCHAR, SQL_WLONGVARCHAR, "NTEXT", 687, 68);
259 : }
260 :
261 10 : strcpy(sql, "CREATE TABLE #tt(k INT");
262 94 : for (t = test_infos; t < test_infos+num_tests; ++t)
263 84 : sprintf(strchr(sql, 0), ",f%u %s", t->num, t->db_type);
264 10 : strcat(sql, ",v INT)");
265 10 : odbc_command(sql);
266 :
267 10 : old_odbc_stmt = odbc_stmt;
268 10 : odbc_stmt = SQL_NULL_HSTMT;
269 :
270 : /* Insert rows ... */
271 :
272 30 : for (i = 0; i < cnt; i++) {
273 : /* MS do not save correctly char -> binary */
274 20 : if (!odbc_driver_is_freetds() && i)
275 0 : continue;
276 :
277 20 : CHKAllocHandle(SQL_HANDLE_STMT, odbc_conn, &odbc_stmt, "S");
278 :
279 20 : strcpy(sql, "INSERT INTO #tt VALUES(?");
280 188 : for (t = test_infos; t < test_infos+num_tests; ++t)
281 168 : strcat(sql, ",?");
282 20 : strcat(sql, ",?)");
283 20 : CHKPrepare(T(sql), SQL_NTS, "S");
284 :
285 20 : CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &key, 0, &vind0, "S");
286 188 : for (t = test_infos; t < test_infos+num_tests; ++t)
287 168 : CHKBindParameter(t->num+1, SQL_PARAM_INPUT, t->c_type, t->sql_type, 0x10000000, 0, t->buf, 0, &t->vind, "S");
288 :
289 20 : CHKBindParameter(num_tests+2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &key, 0, &vind0, "S");
290 :
291 20 : key = i;
292 20 : vind0 = 0;
293 :
294 20 : printf(">> insert... %d\n", i);
295 20 : RetCode = CHKExecute("SINe");
296 228 : while (RetCode == SQL_NEED_DATA) {
297 : char *p;
298 :
299 188 : RetCode = CHKParamData((SQLPOINTER *) & p, "SINe");
300 188 : printf(">> SQLParamData: ptr = %p RetCode = %d\n", (void *) p, RetCode);
301 188 : if (RetCode == SQL_NEED_DATA) {
302 636 : for (t = test_infos; t < test_infos+num_tests && t->buf != p; ++t)
303 : ;
304 168 : assert(t < test_infos+num_tests);
305 168 : if (t->c_type == SQL_C_CHAR || t->c_type == SQL_C_WCHAR) {
306 112 : unsigned char_len = 1;
307 :
308 112 : fill_hex(p, NBYTES, t->gen1, t->gen2);
309 112 : if (t->c_type == SQL_C_WCHAR) {
310 56 : char_len = sizeof(SQLWCHAR);
311 56 : odbc_to_sqlwchar((SQLWCHAR*) p, p, NBYTES * 2);
312 : }
313 :
314 112 : CHKPutData(p, (NBYTES - (i&1)) * char_len, "S");
315 :
316 112 : printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES - (i&1));
317 :
318 112 : CHKPutData(p + (NBYTES - (i&1)) * char_len, (NBYTES + (i&1)) * char_len, "S");
319 :
320 112 : printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES + (i&1));
321 : } else {
322 56 : CHKPutData(p, NBYTES, "S");
323 :
324 56 : printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES);
325 : }
326 : }
327 : }
328 :
329 20 : CHKFreeHandle(SQL_HANDLE_STMT, (SQLHANDLE) odbc_stmt, "S");
330 20 : odbc_stmt = SQL_NULL_HSTMT;
331 : }
332 :
333 : /* Now fetch rows ... */
334 :
335 20 : for (wide = 0; wide < 2; ++wide)
336 60 : for (i = 0; i < cnt; i++) {
337 : /* MS do not save correctly char -> binary */
338 40 : if (!odbc_driver_is_freetds() && i)
339 0 : continue;
340 :
341 :
342 40 : CHKAllocHandle(SQL_HANDLE_STMT, odbc_conn, &odbc_stmt, "S");
343 :
344 40 : if (odbc_db_is_microsoft()) {
345 32 : CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_NONSCROLLABLE, SQL_IS_UINTEGER, "S");
346 32 : CHKSetStmtAttr(SQL_ATTR_CURSOR_SENSITIVITY, (SQLPOINTER) SQL_SENSITIVE, SQL_IS_UINTEGER, "S");
347 : }
348 :
349 40 : strcpy(sql, "SELECT ");
350 376 : for (t = test_infos; t < test_infos+num_tests; ++t)
351 336 : sprintf(strchr(sql, 0), "f%u,", t->num);
352 40 : strcat(sql, "v FROM #tt WHERE k = ?");
353 40 : CHKPrepare(T(sql), SQL_NTS, "S");
354 :
355 40 : CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &i, 0, &vind0, "S");
356 :
357 376 : for (t = test_infos; t < test_infos+num_tests; ++t) {
358 336 : t->vind = SQL_DATA_AT_EXEC;
359 336 : CHKBindCol(t->num, SQL_C_BINARY, NULL, 0, &t->vind, "S");
360 : }
361 40 : CHKBindCol(num_tests+1, SQL_C_LONG, &key, 0, &vind0, "S");
362 :
363 40 : vind0 = 0;
364 :
365 40 : CHKExecute("S");
366 :
367 40 : CHKFetchScroll(SQL_FETCH_NEXT, 0, "S");
368 40 : printf(">> fetch... %d\n", i);
369 :
370 376 : for (t = test_infos; t < test_infos+num_tests; ++t) {
371 336 : if (t->c_type == SQL_C_CHAR || t->c_type == SQL_C_WCHAR)
372 224 : readBlobAsChar(t, i, wide);
373 : else
374 112 : readBlob(t);
375 : }
376 :
377 40 : CHKCloseCursor("S");
378 40 : CHKFreeHandle(SQL_HANDLE_STMT, (SQLHANDLE) odbc_stmt, "S");
379 40 : odbc_stmt = SQL_NULL_HSTMT;
380 : }
381 :
382 10 : odbc_stmt = old_odbc_stmt;
383 :
384 10 : free_tests();
385 10 : odbc_disconnect();
386 :
387 10 : if (!failed)
388 10 : printf("ok!\n");
389 :
390 10 : return failed ? 1 : 0;
391 : }
392 :
|