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