Line data Source code
1 : #include "common.h"
2 :
3 : #if HAVE_SYS_STAT_H
4 : #include <sys/stat.h>
5 : #endif /* HAVE_SYS_STAT_H */
6 :
7 : #include <bkpublic.h>
8 :
9 : #include <freetds/replacements.h>
10 :
11 : static void
12 : do_bind(CS_BLKDESC * blkdesc, int colnum, CS_INT host_format, CS_INT host_type, CS_INT host_maxlen,
13 : void *var_addr,
14 : CS_INT *var_len_addr,
15 : CS_SMALLINT *var_ind_addr );
16 : static void do_one_bind(CS_BLKDESC * blkdesc, int col, const char *name);
17 : static FILE *open_test_file(const char *filename);
18 : typedef enum
19 : {
20 : PART_END,
21 : PART_SQL,
22 : PART_BIND,
23 : PART_OUTPUT,
24 : } part_t;
25 : static part_t read_part_type(FILE * in);
26 : static char *read_part(FILE * in);
27 : static void read_line(char *buf, size_t buf_len, FILE * f);
28 : static char *append_string(char *s1, const char *s2);
29 : static char *get_output(CS_COMMAND * cmd);
30 : static void single_test(CS_CONNECTION * conn, CS_COMMAND * cmd, FILE * in);
31 :
32 : /*
33 : * Static data for insertion
34 : */
35 : static int not_null_bit = 1;
36 : static CS_INT l_not_null_bit = 4;
37 : static CS_SMALLINT i_not_null_bit = 0;
38 :
39 : static char not_null_char[] = "a char";
40 : static CS_INT l_not_null_char = 6;
41 : static CS_SMALLINT i_not_null_char = 0;
42 :
43 : static char not_null_varchar[] = "a varchar";
44 : static CS_INT l_not_null_varchar = 9;
45 : static CS_SMALLINT i_not_null_varchar = 0;
46 :
47 : static char not_null_datetime[] = "Dec 17 2003 3:44PM";
48 : static CS_INT l_not_null_datetime = 19;
49 : static CS_SMALLINT i_not_null_datetime = 0;
50 :
51 : static char not_null_smalldatetime[] = "Dec 17 2003 3:44PM";
52 : static CS_INT l_not_null_smalldatetime = 19;
53 : static CS_SMALLINT i_not_null_smalldatetime = 0;
54 :
55 : static char not_null_money[] = "12.34";
56 : static CS_INT l_not_null_money = 5;
57 : static CS_SMALLINT i_not_null_money = 0;
58 :
59 : static char not_null_smallmoney[] = "12.34";
60 : static CS_INT l_not_null_smallmoney = 5;
61 : static CS_SMALLINT i_not_null_smallmoney = 0;
62 :
63 : static char not_null_float[] = "12.34";
64 : static CS_INT l_not_null_float = 5;
65 : static CS_SMALLINT i_not_null_float = 0;
66 :
67 : static char not_null_real[] = "12.34";
68 : static CS_INT l_not_null_real = 5;
69 : static CS_SMALLINT i_not_null_real = 0;
70 :
71 : static char not_null_decimal[] = "12.34";
72 : static CS_INT l_not_null_decimal = 5;
73 : static CS_SMALLINT i_not_null_decimal = 0;
74 :
75 : static char not_null_numeric[] = "12.34";
76 : static CS_INT l_not_null_numeric = 5;
77 : static CS_SMALLINT i_not_null_numeric = 0;
78 :
79 : static int not_null_int = 1234;
80 : static CS_INT l_not_null_int = 4;
81 : static CS_SMALLINT i_not_null_int = 0;
82 :
83 : static int not_null_smallint = 1234;
84 : static CS_INT l_not_null_smallint = 4;
85 : static CS_SMALLINT i_not_null_smallint = 0;
86 :
87 : static int not_null_tinyint = 123;
88 : static CS_INT l_not_null_tinyint = 4;
89 : static CS_SMALLINT i_not_null_tinyint = 0;
90 :
91 : static CS_INT l_null_char = 0;
92 : static CS_SMALLINT i_null_char = -1;
93 :
94 : static CS_INT l_null_varchar = 0;
95 : static CS_SMALLINT i_null_varchar = -1;
96 :
97 : static CS_INT l_null_datetime = 0;
98 : static CS_SMALLINT i_null_datetime = -1;
99 :
100 : static CS_INT l_null_smalldatetime = 0;
101 : static CS_SMALLINT i_null_smalldatetime = -1;
102 :
103 : static CS_INT l_null_money = 0;
104 : static CS_SMALLINT i_null_money = -1;
105 :
106 : static CS_INT l_null_smallmoney = 0;
107 : static CS_SMALLINT i_null_smallmoney = -1;
108 :
109 : static CS_INT l_null_float = 0;
110 : static CS_SMALLINT i_null_float = -1;
111 :
112 : static CS_INT l_null_real = 0;
113 : static CS_SMALLINT i_null_real = -1;
114 :
115 : static CS_INT l_null_decimal = 0;
116 : static CS_SMALLINT i_null_decimal = -1;
117 :
118 : static CS_INT l_null_numeric = 0;
119 : static CS_SMALLINT i_null_numeric = -1;
120 :
121 : static CS_INT l_null_int = 0;
122 : static CS_SMALLINT i_null_int = -1;
123 :
124 : static CS_INT l_null_smallint = 0;
125 : static CS_SMALLINT i_null_smallint = -1;
126 :
127 : static CS_INT l_null_tinyint = 0;
128 : static CS_SMALLINT i_null_tinyint = -1;
129 :
130 : static char not_null_varbinary[] = "123456789";
131 : static CS_INT l_not_null_varbinary = 9;
132 : static CS_SMALLINT i_not_null_varbinary = 0;
133 :
134 : static void
135 22 : do_binds(CS_BLKDESC *blkdesc, FILE *in)
136 : {
137 : char line[1024];
138 22 : int col = 1;
139 :
140 : for (;;) {
141 690 : read_line(line, sizeof(line), in);
142 356 : if (strcmp(line, "--\n") == 0)
143 22 : return;
144 334 : strtok(line, "\n");
145 334 : do_one_bind(blkdesc, col, line);
146 334 : ++col;
147 : }
148 : }
149 :
150 : static void
151 334 : do_one_bind(CS_BLKDESC *blkdesc, int col, const char *name)
152 : {
153 : #define do_bind(bind_name, fmt, type, len, value) do { \
154 : if (strcmp(#bind_name, name) == 0) { \
155 : do_bind(blkdesc, col, fmt, type, len, value, &l_ ## bind_name, &i_ ## bind_name); \
156 : return; \
157 : } \
158 : } while(0)
159 :
160 : /* non nulls */
161 :
162 334 : do_bind(not_null_bit, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_bit);
163 322 : do_bind(not_null_char, CS_FMT_NULLTERM, CS_CHAR_TYPE, 7, not_null_char);
164 310 : do_bind(not_null_varchar, CS_FMT_NULLTERM, CS_CHAR_TYPE, 10, not_null_varchar);
165 298 : do_bind(not_null_datetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_datetime);
166 286 : do_bind(not_null_smalldatetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_smalldatetime);
167 274 : do_bind(not_null_money, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_money);
168 262 : do_bind(not_null_smallmoney, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_smallmoney);
169 250 : do_bind(not_null_float, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_float);
170 238 : do_bind(not_null_real, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_real);
171 226 : do_bind(not_null_decimal, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_decimal);
172 214 : do_bind(not_null_numeric, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_numeric);
173 202 : do_bind(not_null_int, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_int);
174 190 : do_bind(not_null_smallint, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_smallint);
175 178 : do_bind(not_null_tinyint, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_tinyint);
176 166 : do_bind(not_null_varbinary, CS_FMT_NULLTERM, CS_BINARY_TYPE, 10, not_null_varbinary);
177 :
178 : /* nulls */
179 :
180 156 : do_bind(null_char, CS_FMT_NULLTERM, CS_CHAR_TYPE, 7, not_null_char);
181 144 : do_bind(null_varchar, CS_FMT_NULLTERM, CS_CHAR_TYPE, 10, not_null_varchar);
182 132 : do_bind(null_datetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_datetime);
183 120 : do_bind(null_smalldatetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_smalldatetime);
184 108 : do_bind(null_money, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_money);
185 96 : do_bind(null_smallmoney, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_smallmoney);
186 84 : do_bind(null_float, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_float);
187 72 : do_bind(null_real, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_real);
188 60 : do_bind(null_decimal, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_decimal);
189 48 : do_bind(null_numeric, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_numeric);
190 36 : do_bind(null_int, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_int);
191 24 : do_bind(null_smallint, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_smallint);
192 12 : do_bind(null_tinyint, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_tinyint);
193 : #undef do_bind
194 :
195 0 : fprintf(stderr, "Column %s not found\n", name);
196 0 : exit(1);
197 : }
198 :
199 : static void
200 334 : do_bind(CS_BLKDESC * blkdesc, int colnum, CS_INT host_format, CS_INT host_type, CS_INT host_maxlen,
201 : void *var_addr,
202 : CS_INT *var_len_addr,
203 : CS_SMALLINT *var_ind_addr )
204 : {
205 : CS_DATAFMT datafmt;
206 :
207 334 : check_call(blk_describe, (blkdesc, colnum, &datafmt));
208 :
209 334 : datafmt.format = host_format;
210 334 : datafmt.datatype = host_type;
211 334 : datafmt.maxlength = host_maxlen;
212 334 : datafmt.count = 1;
213 :
214 334 : check_call(blk_bind, (blkdesc, colnum, &datafmt, var_addr, var_len_addr, var_ind_addr ));
215 334 : }
216 :
217 : static const char table_name[] = "all_types_bcp_unittest";
218 :
219 10 : TEST_MAIN()
220 : {
221 : CS_CONTEXT *ctx;
222 : CS_CONNECTION *conn;
223 : CS_COMMAND *cmd;
224 10 : int verbose = 0;
225 : FILE *in;
226 : part_t part;
227 :
228 10 : printf("%s: Retrieve data using array binding \n", __FILE__);
229 : if (verbose) {
230 : printf("Trying login\n");
231 : }
232 10 : in = open_test_file(argc > 1 ? argv[1] : NULL);
233 10 : check_call(try_ctlogin, (&ctx, &conn, &cmd, verbose));
234 :
235 : for (;;) {
236 70 : part = read_part_type(in);
237 40 : if (part == PART_END)
238 : break;
239 30 : assert(part == PART_SQL);
240 :
241 30 : single_test(conn, cmd, in);
242 : }
243 :
244 10 : printf("done\n");
245 :
246 10 : check_call(try_ctlogout, (ctx, conn, cmd, verbose));
247 10 : fclose(in);
248 :
249 10 : return 0;
250 : }
251 :
252 : static void
253 30 : single_test(CS_CONNECTION *conn, CS_COMMAND *cmd, FILE *in)
254 : {
255 : char command[512];
256 : char *create_table_sql, *out1, *out2;
257 : CS_BLKDESC *blkdesc;
258 30 : int count = 0;
259 : int i;
260 : part_t part;
261 : CS_RETCODE ret;
262 :
263 30 : sprintf(command, "if exists (select 1 from sysobjects where type = 'U' and name = '%s') drop table %s",
264 : table_name, table_name);
265 :
266 30 : check_call(run_command, (cmd, command));
267 :
268 30 : create_table_sql = read_part(in);
269 30 : ret = run_command(cmd, create_table_sql);
270 30 : free(create_table_sql);
271 :
272 : /* on error skip the test */
273 30 : if (ret != CS_SUCCEED) {
274 8 : part = read_part_type(in);
275 8 : assert(part == PART_BIND);
276 8 : free(read_part(in));
277 :
278 8 : part = read_part_type(in);
279 8 : assert(part == PART_OUTPUT);
280 8 : free(read_part(in));
281 8 : return;
282 : }
283 :
284 22 : sprintf(command, "delete from %s", table_name);
285 22 : check_call(run_command, (cmd, command));
286 :
287 22 : check_call(blk_alloc, (conn, BLK_VERSION_100, &blkdesc));
288 :
289 22 : check_call(blk_init, (blkdesc, CS_BLK_IN, (char *) table_name, CS_NULLTERM));
290 :
291 22 : part = read_part_type(in);
292 22 : assert(part == PART_BIND);
293 :
294 22 : do_binds(blkdesc, in);
295 :
296 22 : part = read_part_type(in);
297 22 : assert(part == PART_OUTPUT);
298 :
299 22 : printf("Sending same row 10 times... \n");
300 242 : for (i = 0; i < 10; i++) {
301 220 : check_call(blk_rowxfer, (blkdesc));
302 : }
303 :
304 22 : check_call(blk_done, (blkdesc, CS_BLK_ALL, &count));
305 :
306 22 : blk_drop(blkdesc);
307 :
308 22 : printf("%d rows copied.\n", count);
309 :
310 22 : out1 = read_part(in);
311 22 : out2 = get_output(cmd);
312 22 : if (strcmp(out1, out2) != 0) {
313 0 : fprintf(stderr, "Wrong output\n-- expected --\n%s\n-- got --\n%s\n--\n", out1, out2);
314 0 : exit(1);
315 : }
316 22 : free(out1);
317 22 : free(out2);
318 : }
319 :
320 : static char *
321 22 : get_output(CS_COMMAND *cmd)
322 : {
323 : char command[512];
324 :
325 : CS_RETCODE ret;
326 : CS_RETCODE results_ret;
327 : CS_DATAFMT datafmt;
328 : CS_INT datalength;
329 22 : CS_SMALLINT *inds = NULL;
330 22 : CS_INT count, row_count = 0;
331 : CS_INT result_type;
332 22 : CS_CHAR *data = NULL;
333 : CS_INT num_cols;
334 : CS_INT i;
335 22 : char *out = strdup("");
336 :
337 22 : assert(out != NULL);
338 :
339 22 : sprintf(command, "select distinct * from %s", table_name);
340 22 : check_call(ct_command, (cmd, CS_LANG_CMD, command, CS_NULLTERM, CS_UNUSED));
341 :
342 22 : check_call(ct_send, (cmd));
343 22 : while ((results_ret = ct_results(cmd, &result_type)) == CS_SUCCEED) {
344 44 : switch ((int) result_type) {
345 : case CS_CMD_SUCCEED:
346 : break;
347 : case CS_CMD_DONE:
348 : break;
349 0 : case CS_CMD_FAIL:
350 0 : fprintf(stderr, "ct_results() result_type CS_CMD_FAIL.\n");
351 0 : exit(1);
352 22 : case CS_ROW_RESULT:
353 22 : check_call(ct_res_info, (cmd, CS_NUMDATA, &num_cols, CS_UNUSED, NULL));
354 22 : data = malloc(num_cols * 256);
355 22 : assert(data != NULL);
356 22 : inds = calloc(num_cols, sizeof(*inds));
357 22 : assert(inds != NULL);
358 334 : for (i = 0; i < num_cols; i++) {
359 334 : datafmt.datatype = CS_CHAR_TYPE;
360 334 : datafmt.format = CS_FMT_NULLTERM;
361 334 : datafmt.maxlength = 256;
362 334 : datafmt.count = 1;
363 334 : datafmt.locale = NULL;
364 334 : check_call(ct_bind, (cmd, i + 1, &datafmt, data + 256 * i, &datalength, &inds[i]));
365 : }
366 :
367 44 : while ((ret = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count)) == CS_SUCCEED) {
368 22 : row_count += count;
369 356 : for (i = 0; i < num_cols; i++) {
370 334 : if (!inds[i])
371 178 : out = append_string(out, data + 256 * i);
372 : else
373 156 : out = append_string(out, "NULL");
374 334 : out = append_string(out, "\n");
375 : }
376 : }
377 22 : switch ((int) ret) {
378 : case CS_END_DATA:
379 : break;
380 0 : case CS_FAIL:
381 0 : fprintf(stderr, "ct_fetch() returned CS_FAIL.\n");
382 0 : exit(1);
383 0 : case CS_ROW_FAIL:
384 0 : fprintf(stderr, "ct_fetch() CS_ROW_FAIL on row %d.\n", row_count);
385 0 : exit(1);
386 0 : default:
387 0 : fprintf(stderr, "ct_fetch() unexpected return.\n");
388 0 : exit(1);
389 : }
390 : break;
391 0 : case CS_COMPUTE_RESULT:
392 0 : fprintf(stderr, "ct_results() unexpected CS_COMPUTE_RESULT.\n");
393 0 : exit(1);
394 0 : default:
395 0 : fprintf(stderr, "ct_results() unexpected result_type.\n");
396 0 : exit(1);
397 : }
398 : }
399 22 : switch ((int) results_ret) {
400 : case CS_END_RESULTS:
401 : break;
402 0 : case CS_FAIL:
403 0 : fprintf(stderr, "ct_results() failed.\n");
404 0 : exit(1);
405 : break;
406 0 : default:
407 0 : fprintf(stderr, "ct_results() unexpected return.\n");
408 0 : exit(1);
409 : }
410 :
411 22 : free(data);
412 22 : free(inds);
413 22 : return out;
414 : }
415 :
416 :
417 : static FILE *
418 10 : open_test_file(const char *filename)
419 : {
420 10 : FILE *input_file = NULL;
421 : char in_file[256];
422 :
423 : /* If no filename requested, try blk_in.in in both the expected location and the current directory. */
424 10 : if (filename)
425 0 : input_file = fopen(filename, "r");
426 : else {
427 10 : snprintf(in_file, sizeof(in_file), "%s/blk_in.in", FREETDS_SRCDIR);
428 10 : filename = in_file;
429 10 : input_file = fopen(filename, "r");
430 10 : if (!input_file) {
431 0 : filename = "blk_in.in";
432 0 : input_file = fopen(filename, "r");
433 : }
434 : }
435 10 : if (!input_file) {
436 0 : fprintf(stderr, "could not open %s\n", filename);
437 0 : exit(1);
438 : }
439 10 : return input_file;
440 : }
441 :
442 : static part_t
443 100 : read_part_type(FILE *in)
444 : {
445 : char line[1024];
446 : part_t part;
447 :
448 100 : read_line(line, sizeof(line), in);
449 100 : if (strncmp(line, "end", 3) == 0)
450 : return PART_END;
451 :
452 90 : if (strcmp(line, "sql\n") == 0)
453 : part = PART_SQL;
454 60 : else if (strcmp(line, "bind\n") == 0)
455 : part = PART_BIND;
456 30 : else if (strcmp(line, "output\n") == 0)
457 : part = PART_OUTPUT;
458 : else {
459 0 : fprintf(stderr, "Invalid part: %s\n", line);
460 0 : exit(1);
461 : }
462 90 : read_line(line, sizeof(line), in);
463 90 : if (strcmp(line, "--\n") != 0) {
464 0 : fprintf(stderr, "Error reading line\n");
465 0 : exit(1);
466 : }
467 : return part;
468 : }
469 :
470 : static char *
471 68 : read_part(FILE *in)
472 : {
473 : char line[1024];
474 68 : char *part = strdup("");
475 :
476 68 : assert(part != NULL);
477 : for (;;) {
478 3586 : read_line(line, sizeof(line), in);
479 3654 : if (strcmp(line, "--\n") == 0)
480 68 : return part;
481 3586 : part = append_string(part, line);
482 : }
483 : }
484 :
485 : static void
486 4200 : read_line(char *buf, size_t buf_len, FILE *f)
487 : {
488 4200 : if (fgets(buf, buf_len, f) == NULL || ferror(f)) {
489 0 : fprintf(stderr, "Error reading line\n");
490 0 : exit(1);
491 : }
492 4200 : }
493 :
494 : static char *
495 4254 : append_string(char *s1, const char *s2)
496 : {
497 4254 : assert(s1);
498 4254 : assert(s2);
499 4254 : s1 = realloc(s1, strlen(s1) + strlen(s2) + 1);
500 4254 : assert(s1 != NULL);
501 4254 : strcat(s1, s2);
502 4254 : return s1;
503 : }
|