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 CS_RETCODE
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(void);
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 20 : do_binds(CS_BLKDESC *blkdesc, FILE *in)
136 : {
137 : char line[1024];
138 20 : int col = 1;
139 :
140 : for (;;) {
141 580 : read_line(line, sizeof(line), in);
142 300 : if (strcmp(line, "--\n") == 0)
143 20 : return;
144 280 : strtok(line, "\n");
145 280 : do_one_bind(blkdesc, col, line);
146 280 : ++col;
147 : }
148 : }
149 :
150 : static void
151 280 : 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 280 : do_bind(not_null_bit, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_bit);
163 270 : do_bind(not_null_char, CS_FMT_NULLTERM, CS_CHAR_TYPE, 7, not_null_char);
164 260 : do_bind(not_null_varchar, CS_FMT_NULLTERM, CS_CHAR_TYPE, 10, not_null_varchar);
165 250 : do_bind(not_null_datetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_datetime);
166 240 : do_bind(not_null_smalldatetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_smalldatetime);
167 230 : do_bind(not_null_money, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_money);
168 220 : do_bind(not_null_smallmoney, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_smallmoney);
169 210 : do_bind(not_null_float, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_float);
170 200 : do_bind(not_null_real, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_real);
171 190 : do_bind(not_null_decimal, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_decimal);
172 180 : do_bind(not_null_numeric, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_numeric);
173 170 : do_bind(not_null_int, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_int);
174 160 : do_bind(not_null_smallint, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_smallint);
175 150 : do_bind(not_null_tinyint, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_tinyint);
176 140 : do_bind(not_null_varbinary, CS_FMT_NULLTERM, CS_BINARY_TYPE, 10, not_null_varbinary);
177 :
178 : /* nulls */
179 :
180 130 : do_bind(null_char, CS_FMT_NULLTERM, CS_CHAR_TYPE, 7, not_null_char);
181 120 : do_bind(null_varchar, CS_FMT_NULLTERM, CS_CHAR_TYPE, 10, not_null_varchar);
182 110 : do_bind(null_datetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_datetime);
183 100 : do_bind(null_smalldatetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_smalldatetime);
184 90 : do_bind(null_money, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_money);
185 80 : do_bind(null_smallmoney, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_smallmoney);
186 70 : do_bind(null_float, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_float);
187 60 : do_bind(null_real, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_real);
188 50 : do_bind(null_decimal, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_decimal);
189 40 : do_bind(null_numeric, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_numeric);
190 30 : do_bind(null_int, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_int);
191 20 : do_bind(null_smallint, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_smallint);
192 10 : 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 CS_RETCODE
200 280 : 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 : CS_RETCODE ret;
207 :
208 280 : ret = blk_describe(blkdesc, colnum, &datafmt);
209 280 : if (ret != CS_SUCCEED) {
210 0 : fprintf(stderr, "blk_describe(%d) failed", colnum);
211 0 : return ret;
212 : }
213 :
214 280 : datafmt.format = host_format;
215 280 : datafmt.datatype = host_type;
216 280 : datafmt.maxlength = host_maxlen;
217 280 : datafmt.count = 1;
218 :
219 280 : ret = blk_bind(blkdesc, colnum, &datafmt, var_addr, var_len_addr, var_ind_addr );
220 280 : if (ret != CS_SUCCEED) {
221 0 : fprintf(stderr, "blk_bind() failed\n");
222 0 : return ret;
223 : }
224 : return ret;
225 : }
226 :
227 : static const char table_name[] = "all_types_bcp_unittest";
228 :
229 : int
230 10 : main(void)
231 : {
232 : CS_CONTEXT *ctx;
233 : CS_CONNECTION *conn;
234 : CS_COMMAND *cmd;
235 10 : int verbose = 0;
236 : FILE *in;
237 : part_t part;
238 :
239 10 : printf("%s: Retrieve data using array binding \n", __FILE__);
240 : if (verbose) {
241 : printf("Trying login\n");
242 : }
243 10 : in = open_test_file();
244 10 : check_call(try_ctlogin, (&ctx, &conn, &cmd, verbose));
245 :
246 : for (;;) {
247 50 : part = read_part_type(in);
248 30 : if (part == PART_END)
249 : break;
250 20 : assert(part == PART_SQL);
251 :
252 20 : single_test(conn, cmd, in);
253 : }
254 :
255 10 : printf("done\n");
256 :
257 10 : check_call(try_ctlogout, (ctx, conn, cmd, verbose));
258 10 : fclose(in);
259 :
260 : return 0;
261 : }
262 :
263 : static void
264 20 : single_test(CS_CONNECTION *conn, CS_COMMAND *cmd, FILE *in)
265 : {
266 : char command[512];
267 : char *create_table_sql, *out1, *out2;
268 : CS_BLKDESC *blkdesc;
269 20 : int count = 0;
270 : int i;
271 : part_t part;
272 :
273 20 : sprintf(command, "if exists (select 1 from sysobjects where type = 'U' and name = '%s') drop table %s",
274 : table_name, table_name);
275 :
276 20 : check_call(run_command, (cmd, command));
277 :
278 20 : create_table_sql = read_part(in);
279 20 : check_call(run_command, (cmd, create_table_sql));
280 20 : free(create_table_sql);
281 :
282 20 : sprintf(command, "delete from %s", table_name);
283 20 : check_call(run_command, (cmd, command));
284 :
285 20 : check_call(blk_alloc, (conn, BLK_VERSION_100, &blkdesc));
286 :
287 20 : check_call(blk_init, (blkdesc, CS_BLK_IN, (char *) table_name, CS_NULLTERM));
288 :
289 20 : part = read_part_type(in);
290 20 : assert(part == PART_BIND);
291 :
292 20 : do_binds(blkdesc, in);
293 :
294 20 : part = read_part_type(in);
295 20 : assert(part == PART_OUTPUT);
296 :
297 20 : printf("Sending same row 10 times... \n");
298 220 : for (i = 0; i < 10; i++) {
299 200 : check_call(blk_rowxfer, (blkdesc));
300 : }
301 :
302 20 : check_call(blk_done, (blkdesc, CS_BLK_ALL, &count));
303 :
304 20 : blk_drop(blkdesc);
305 :
306 20 : printf("%d rows copied.\n", count);
307 :
308 20 : out1 = read_part(in);
309 20 : out2 = get_output(cmd);
310 20 : if (strcmp(out1, out2) != 0) {
311 0 : fprintf(stderr, "Wrong output\n--\n%s\n--\n%s\n--\n", out1, out2);
312 0 : exit(1);
313 : }
314 20 : free(out1);
315 20 : free(out2);
316 20 : }
317 :
318 : static char *
319 20 : get_output(CS_COMMAND *cmd)
320 : {
321 : char command[512];
322 :
323 : CS_RETCODE ret;
324 : CS_RETCODE results_ret;
325 : CS_DATAFMT datafmt;
326 : CS_INT datalength;
327 20 : CS_SMALLINT *inds = NULL;
328 20 : CS_INT count, row_count = 0;
329 : CS_INT result_type;
330 20 : CS_CHAR *data = NULL;
331 : CS_INT num_cols;
332 : CS_INT i;
333 20 : char *out = strdup("");
334 :
335 20 : assert(out != NULL);
336 :
337 20 : sprintf(command, "select distinct * from %s", table_name);
338 20 : check_call(ct_command, (cmd, CS_LANG_CMD, command, CS_NULLTERM, CS_UNUSED));
339 :
340 20 : check_call(ct_send, (cmd));
341 20 : while ((results_ret = ct_results(cmd, &result_type)) == CS_SUCCEED) {
342 40 : switch ((int) result_type) {
343 : case CS_CMD_SUCCEED:
344 : break;
345 : case CS_CMD_DONE:
346 : break;
347 0 : case CS_CMD_FAIL:
348 0 : fprintf(stderr, "ct_results() result_type CS_CMD_FAIL.\n");
349 0 : exit(1);
350 20 : case CS_ROW_RESULT:
351 20 : check_call(ct_res_info, (cmd, CS_NUMDATA, &num_cols, CS_UNUSED, NULL));
352 20 : data = malloc(num_cols * 256);
353 20 : assert(data != NULL);
354 20 : inds = calloc(num_cols, sizeof(*inds));
355 20 : assert(inds != NULL);
356 280 : for (i = 0; i < num_cols; i++) {
357 280 : datafmt.datatype = CS_CHAR_TYPE;
358 280 : datafmt.format = CS_FMT_NULLTERM;
359 280 : datafmt.maxlength = 256;
360 280 : datafmt.count = 1;
361 280 : datafmt.locale = NULL;
362 280 : check_call(ct_bind, (cmd, i + 1, &datafmt, data + 256 * i, &datalength, &inds[i]));
363 : }
364 :
365 40 : while ((ret = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count)) == CS_SUCCEED) {
366 20 : row_count += count;
367 300 : for (i = 0; i < num_cols; i++) {
368 280 : if (!inds[i])
369 150 : out = append_string(out, data + 256 * i);
370 : else
371 130 : out = append_string(out, "NULL");
372 280 : out = append_string(out, "\n");
373 : }
374 : }
375 20 : switch ((int) ret) {
376 : case CS_END_DATA:
377 : break;
378 0 : case CS_FAIL:
379 0 : fprintf(stderr, "ct_fetch() returned CS_FAIL.\n");
380 0 : exit(1);
381 0 : case CS_ROW_FAIL:
382 0 : fprintf(stderr, "ct_fetch() CS_ROW_FAIL on row %d.\n", row_count);
383 0 : exit(1);
384 0 : default:
385 0 : fprintf(stderr, "ct_fetch() unexpected return.\n");
386 0 : exit(1);
387 : }
388 : break;
389 0 : case CS_COMPUTE_RESULT:
390 0 : fprintf(stderr, "ct_results() unexpected CS_COMPUTE_RESULT.\n");
391 0 : exit(1);
392 0 : default:
393 0 : fprintf(stderr, "ct_results() unexpected result_type.\n");
394 0 : exit(1);
395 : }
396 : }
397 20 : switch ((int) results_ret) {
398 : case CS_END_RESULTS:
399 : break;
400 0 : case CS_FAIL:
401 0 : fprintf(stderr, "ct_results() failed.\n");
402 0 : exit(1);
403 : break;
404 0 : default:
405 0 : fprintf(stderr, "ct_results() unexpected return.\n");
406 0 : exit(1);
407 : }
408 :
409 20 : free(data);
410 20 : free(inds);
411 20 : return out;
412 : }
413 :
414 :
415 : static FILE *
416 10 : open_test_file(void)
417 : {
418 : FILE *input_file;
419 : char in_file[256];
420 :
421 10 : snprintf(in_file, sizeof(in_file), "%s/blk_in.in", FREETDS_SRCDIR);
422 :
423 10 : input_file = fopen(in_file, "r");
424 10 : if (!input_file) {
425 0 : strcpy(in_file, "blk_in.in");
426 0 : input_file = fopen(in_file, "r");
427 : }
428 10 : if (!input_file) {
429 0 : fprintf(stderr, "could not open %s\n", in_file);
430 0 : exit(1);
431 : }
432 10 : return input_file;
433 : }
434 :
435 : static part_t
436 70 : read_part_type(FILE *in)
437 : {
438 : char line[1024];
439 : part_t part;
440 :
441 70 : read_line(line, sizeof(line), in);
442 70 : if (strncmp(line, "end", 3) == 0)
443 : return PART_END;
444 :
445 60 : if (strcmp(line, "sql\n") == 0)
446 : part = PART_SQL;
447 40 : else if (strcmp(line, "bind\n") == 0)
448 : part = PART_BIND;
449 20 : else if (strcmp(line, "output\n") == 0)
450 : part = PART_OUTPUT;
451 : else {
452 0 : fprintf(stderr, "Invalid part: %s\n", line);
453 0 : exit(1);
454 : }
455 60 : read_line(line, sizeof(line), in);
456 60 : if (strcmp(line, "--\n") != 0) {
457 0 : fprintf(stderr, "Error reading line\n");
458 0 : exit(1);
459 : }
460 : return part;
461 : }
462 :
463 : static char *
464 40 : read_part(FILE *in)
465 : {
466 : char line[1024];
467 40 : char *part = strdup("");
468 :
469 40 : assert(part != NULL);
470 : for (;;) {
471 1700 : read_line(line, sizeof(line), in);
472 1740 : if (strcmp(line, "--\n") == 0)
473 40 : return part;
474 1700 : part = append_string(part, line);
475 : }
476 : }
477 :
478 : static void
479 2170 : read_line(char *buf, size_t buf_len, FILE *f)
480 : {
481 2170 : if (fgets(buf, buf_len, f) == NULL || ferror(f)) {
482 0 : fprintf(stderr, "Error reading line\n");
483 0 : exit(1);
484 : }
485 2170 : }
486 :
487 : static char *
488 2260 : append_string(char *s1, const char *s2)
489 : {
490 2260 : assert(s1);
491 2260 : assert(s2);
492 2260 : s1 = realloc(s1, strlen(s1) + strlen(s2) + 1);
493 2260 : assert(s1 != NULL);
494 2260 : strcat(s1, s2);
495 2260 : return s1;
496 : }
|