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, CS_INT * var_len_addr, CS_SMALLINT * var_ind_addr);
14 : static void do_one_bind(CS_BLKDESC * blkdesc, int col, const char *name);
15 : static void do_type_bind(CS_BLKDESC * blkdesc, int col, const char *tok);
16 : static void free_dynamic_bounded(void);
17 : static void sendrow(CS_BLKDESC * blkdesc, const char *tok);
18 : static FILE *open_test_file(const char *filename);
19 : typedef enum
20 : {
21 : PART_END,
22 : PART_SQL,
23 : PART_BIND,
24 : PART_OUTPUT,
25 : PART_SELECT,
26 : } part_t;
27 : static part_t read_part_type(FILE * in);
28 : static char *read_part(FILE * in);
29 : static void read_line(char *buf, size_t buf_len, FILE * f);
30 : static char *append_string(char *s1, const char *s2);
31 : static char *get_output(CS_COMMAND * cmd, bool distinct, const char *select);
32 : static void single_test(CS_CONNECTION * conn, CS_COMMAND * cmd, FILE * in);
33 :
34 : static CS_CONTEXT *ctx;
35 :
36 : /*
37 : * Static data for insertion
38 : */
39 : static int not_null_bit = 1;
40 : static CS_INT l_not_null_bit = 4;
41 : static CS_SMALLINT i_not_null_bit = 0;
42 :
43 : static char not_null_char[] = "a char";
44 : static CS_INT l_not_null_char = 6;
45 : static CS_SMALLINT i_not_null_char = 0;
46 :
47 : static char not_null_varchar[] = "a varchar";
48 : static CS_INT l_not_null_varchar = 9;
49 : static CS_SMALLINT i_not_null_varchar = 0;
50 :
51 : static char not_null_datetime[] = "Dec 17 2003 3:44PM";
52 : static CS_INT l_not_null_datetime = 19;
53 : static CS_SMALLINT i_not_null_datetime = 0;
54 :
55 : static char not_null_smalldatetime[] = "Dec 17 2003 3:44PM";
56 : static CS_INT l_not_null_smalldatetime = 19;
57 : static CS_SMALLINT i_not_null_smalldatetime = 0;
58 :
59 : static char not_null_money[] = "12.34";
60 : static CS_INT l_not_null_money = 5;
61 : static CS_SMALLINT i_not_null_money = 0;
62 :
63 : static char not_null_smallmoney[] = "12.34";
64 : static CS_INT l_not_null_smallmoney = 5;
65 : static CS_SMALLINT i_not_null_smallmoney = 0;
66 :
67 : static char not_null_float[] = "12.34";
68 : static CS_INT l_not_null_float = 5;
69 : static CS_SMALLINT i_not_null_float = 0;
70 :
71 : static char not_null_real[] = "12.25";
72 : static CS_INT l_not_null_real = 5;
73 : static CS_SMALLINT i_not_null_real = 0;
74 :
75 : static char not_null_decimal[] = "12.34";
76 : static CS_INT l_not_null_decimal = 5;
77 : static CS_SMALLINT i_not_null_decimal = 0;
78 :
79 : static char not_null_numeric[] = "12.34";
80 : static CS_INT l_not_null_numeric = 5;
81 : static CS_SMALLINT i_not_null_numeric = 0;
82 :
83 : static int not_null_int = 1234;
84 : static CS_INT l_not_null_int = 4;
85 : static CS_SMALLINT i_not_null_int = 0;
86 :
87 : static int not_null_smallint = 1234;
88 : static CS_INT l_not_null_smallint = 4;
89 : static CS_SMALLINT i_not_null_smallint = 0;
90 :
91 : static int not_null_tinyint = 123;
92 : static CS_INT l_not_null_tinyint = 4;
93 : static CS_SMALLINT i_not_null_tinyint = 0;
94 :
95 : static CS_INT l_null_char = 0;
96 : static CS_SMALLINT i_null_char = -1;
97 :
98 : static CS_INT l_null_varchar = 0;
99 : static CS_SMALLINT i_null_varchar = -1;
100 :
101 : static CS_INT l_null_datetime = 0;
102 : static CS_SMALLINT i_null_datetime = -1;
103 :
104 : static CS_INT l_null_smalldatetime = 0;
105 : static CS_SMALLINT i_null_smalldatetime = -1;
106 :
107 : static CS_INT l_null_money = 0;
108 : static CS_SMALLINT i_null_money = -1;
109 :
110 : static CS_INT l_null_smallmoney = 0;
111 : static CS_SMALLINT i_null_smallmoney = -1;
112 :
113 : static CS_INT l_null_float = 0;
114 : static CS_SMALLINT i_null_float = -1;
115 :
116 : static CS_INT l_null_real = 0;
117 : static CS_SMALLINT i_null_real = -1;
118 :
119 : static CS_INT l_null_decimal = 0;
120 : static CS_SMALLINT i_null_decimal = -1;
121 :
122 : static CS_INT l_null_numeric = 0;
123 : static CS_SMALLINT i_null_numeric = -1;
124 :
125 : static CS_INT l_null_int = 0;
126 : static CS_SMALLINT i_null_int = -1;
127 :
128 : static CS_INT l_null_smallint = 0;
129 : static CS_SMALLINT i_null_smallint = -1;
130 :
131 : static CS_INT l_null_tinyint = 0;
132 : static CS_SMALLINT i_null_tinyint = -1;
133 :
134 : static char not_null_varbinary[] = "123456789";
135 : static CS_INT l_not_null_varbinary = 9;
136 : static CS_SMALLINT i_not_null_varbinary = 0;
137 :
138 : static void
139 102 : do_binds(CS_BLKDESC *blkdesc, FILE *in, bool *rows_sent)
140 : {
141 : char line[1024];
142 102 : int col = 1;
143 :
144 102 : *rows_sent = false;
145 : for (;;) {
146 : const char *tok;
147 :
148 1756 : read_line(line, sizeof(line), in);
149 1756 : if (strcmp(line, "--\n") == 0)
150 102 : return;
151 1654 : tok = strtok(line, " \t\n");
152 :
153 1654 : if (strcmp(tok, "--") == 0) {
154 : /* comment */
155 190 : continue;
156 1464 : } else if (strncmp(tok, "SENDROW", 7) == 0) {
157 302 : sendrow(blkdesc, tok);
158 302 : col = 0;
159 302 : *rows_sent = true;
160 1162 : } else if (strncmp(tok, "CS_", 3) == 0) {
161 828 : do_type_bind(blkdesc, col, tok);
162 : } else {
163 334 : do_one_bind(blkdesc, col, line);
164 : }
165 1464 : ++col;
166 : }
167 : }
168 :
169 : static void
170 334 : do_one_bind(CS_BLKDESC *blkdesc, int col, const char *name)
171 : {
172 : #define do_bind(bind_name, fmt, type, len, value) do { \
173 : if (strcmp(#bind_name, name) == 0) { \
174 : do_bind(blkdesc, col, fmt, type, len, value, &l_ ## bind_name, &i_ ## bind_name); \
175 : return; \
176 : } \
177 : } while(0)
178 :
179 : /* non nulls */
180 :
181 334 : do_bind(not_null_bit, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_bit);
182 322 : do_bind(not_null_char, CS_FMT_NULLTERM, CS_CHAR_TYPE, 7, not_null_char);
183 310 : do_bind(not_null_varchar, CS_FMT_NULLTERM, CS_CHAR_TYPE, 10, not_null_varchar);
184 298 : do_bind(not_null_datetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_datetime);
185 286 : do_bind(not_null_smalldatetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_smalldatetime);
186 274 : do_bind(not_null_money, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_money);
187 262 : do_bind(not_null_smallmoney, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_smallmoney);
188 250 : do_bind(not_null_float, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_float);
189 238 : do_bind(not_null_real, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_real);
190 226 : do_bind(not_null_decimal, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_decimal);
191 214 : do_bind(not_null_numeric, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_numeric);
192 202 : do_bind(not_null_int, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_int);
193 190 : do_bind(not_null_smallint, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_smallint);
194 178 : do_bind(not_null_tinyint, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_tinyint);
195 166 : do_bind(not_null_varbinary, CS_FMT_NULLTERM, CS_BINARY_TYPE, 10, not_null_varbinary);
196 :
197 : /* nulls */
198 :
199 156 : do_bind(null_char, CS_FMT_NULLTERM, CS_CHAR_TYPE, 7, not_null_char);
200 144 : do_bind(null_varchar, CS_FMT_NULLTERM, CS_CHAR_TYPE, 10, not_null_varchar);
201 132 : do_bind(null_datetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_datetime);
202 120 : do_bind(null_smalldatetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_smalldatetime);
203 108 : do_bind(null_money, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_money);
204 96 : do_bind(null_smallmoney, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_smallmoney);
205 84 : do_bind(null_float, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_float);
206 72 : do_bind(null_real, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_real);
207 60 : do_bind(null_decimal, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_decimal);
208 48 : do_bind(null_numeric, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_numeric);
209 36 : do_bind(null_int, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_int);
210 24 : do_bind(null_smallint, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_smallint);
211 12 : do_bind(null_tinyint, CS_FMT_UNUSED, CS_INT_TYPE, 4, ¬_null_tinyint);
212 : #undef do_bind
213 :
214 0 : fprintf(stderr, "Column %s not found\n", name);
215 0 : exit(1);
216 : }
217 :
218 : typedef struct bound_value
219 : {
220 : struct bound_value *next;
221 : CS_INT varlen;
222 : CS_SMALLINT ind;
223 : void *value;
224 : } bound_value;
225 :
226 : static bound_value *dynamic_bounded = NULL;
227 :
228 : static void
229 102 : free_dynamic_bounded(void)
230 : {
231 1032 : while (dynamic_bounded) {
232 828 : bound_value *next = dynamic_bounded->next;
233 :
234 828 : free(dynamic_bounded->value);
235 828 : free(dynamic_bounded);
236 828 : dynamic_bounded = next;
237 : }
238 102 : }
239 :
240 : static CS_INT
241 828 : type_from_name(const char *name)
242 : {
243 : #define TYPE(t) if (strcmp(name, #t) == 0) return t;
244 828 : TYPE(CS_CHAR_TYPE);
245 322 : TYPE(CS_LONGCHAR_TYPE);
246 312 : TYPE(CS_VARCHAR_TYPE);
247 292 : TYPE(CS_BINARY_TYPE);
248 268 : TYPE(CS_LONGBINARY_TYPE);
249 248 : TYPE(CS_VARBINARY_TYPE);
250 204 : TYPE(CS_INT_TYPE);
251 170 : TYPE(CS_DATETIME_TYPE);
252 140 : TYPE(CS_DATETIME4_TYPE);
253 120 : TYPE(CS_DATE_TYPE);
254 102 : TYPE(CS_TIME_TYPE);
255 84 : TYPE(CS_BIGDATETIME_TYPE);
256 38 : TYPE(CS_BIGTIME_TYPE);
257 20 : TYPE(CS_NUMERIC_TYPE);
258 : #undef TYPE
259 0 : fprintf(stderr, "Unhandled type %s\n", name);
260 0 : exit(1);
261 : }
262 :
263 : /*
264 : * Bind a value of a given type.
265 : * Syntax is "<type> <maxlen> <value>", value is converted from string.
266 : */
267 : static void
268 828 : do_type_bind(CS_BLKDESC *blkdesc, int col, const char *tok)
269 : {
270 828 : CS_INT type = type_from_name(tok);
271 828 : const char *maxlen_str = strtok(NULL, " \t\n");
272 :
273 : /* "UNUSED" means length not specified (CS_UNUSED), only for fixed types */
274 828 : bool unused_len = strcmp(maxlen_str, "UNUSED") == 0;
275 1596 : CS_INT maxlen = unused_len ? 64 : atoi(maxlen_str);
276 828 : char *value = strdup(strtok(NULL, "\n"));
277 828 : bound_value *bound = calloc(1, sizeof(*bound));
278 :
279 828 : assert(value);
280 828 : assert(bound);
281 :
282 828 : if (strncmp(value, "\"\"\"", 3) == 0) {
283 : char *p;
284 :
285 20 : memmove(value, value + 3, strlen(value + 2));
286 20 : p = strstr(value, "\"\"\"");
287 20 : if (p)
288 20 : *p = '\0';
289 : }
290 828 : bound->varlen = strlen(value);
291 828 : bound->ind = 0;
292 828 : bound->value = value;
293 828 : bound->next = dynamic_bounded;
294 828 : dynamic_bounded = bound;
295 :
296 828 : if (type == CS_CHAR_TYPE) {
297 506 : do_bind(blkdesc, col, CS_FMT_NULLTERM, CS_CHAR_TYPE, maxlen, value, &bound->varlen, &bound->ind);
298 506 : return;
299 : } else {
300 : CS_DATAFMT srcfmt, destfmt;
301 : /* large enough for CS_VARCHAR/CS_VARBINARY */
302 322 : void *data = calloc(1, 512);
303 :
304 322 : assert(data);
305 322 : memset(&srcfmt, 0, sizeof(srcfmt));
306 : srcfmt.datatype = CS_CHAR_TYPE;
307 322 : srcfmt.maxlength = bound->varlen;
308 322 : memset(&destfmt, 0, sizeof(destfmt));
309 322 : destfmt.datatype = type;
310 322 : destfmt.maxlength = (type == CS_VARCHAR_TYPE || type == CS_VARBINARY_TYPE) ? 512 : 64;
311 : destfmt.format = CS_FMT_UNUSED;
312 322 : if (type == CS_NUMERIC_TYPE) {
313 20 : destfmt.precision = 10;
314 20 : destfmt.scale = 2;
315 : }
316 322 : check_call(cs_convert, (ctx, &srcfmt, value, &destfmt, data, &bound->varlen));
317 322 : if (unused_len)
318 60 : bound->varlen = CS_UNUSED;
319 322 : bound->value = data;
320 322 : free(value);
321 322 : do_bind(blkdesc, col, CS_FMT_UNUSED, type, maxlen, data, &bound->varlen, &bound->ind);
322 : }
323 : }
324 :
325 : static void
326 302 : sendrow(CS_BLKDESC *blkdesc, const char *tok)
327 : {
328 : const char *errtype_str;
329 : ct_message_type errtype;
330 : CS_INT number;
331 : const char *message;
332 :
333 302 : ct_reset_last_message();
334 302 : if (strcmp(tok, "SENDROWERROR") == 0)
335 90 : check_fail(blk_rowxfer, (blkdesc));
336 : else
337 212 : check_call(blk_rowxfer, (blkdesc));
338 :
339 302 : errtype_str = strtok(NULL, " \t\n");
340 302 : if (!errtype_str) {
341 112 : check_last_message(CTMSG_NONE, 0, NULL);
342 112 : return;
343 : }
344 :
345 190 : if (strcmp(errtype_str, "CLIENT") == 0)
346 : errtype = CTMSG_CLIENT;
347 190 : else if (strcmp(errtype_str, "CLIENT2") == 0)
348 : errtype = CTMSG_CLIENT2;
349 0 : else if (strcmp(errtype_str, "SERVER") == 0)
350 : errtype = CTMSG_SERVER;
351 0 : else if (strcmp(errtype_str, "CSLIB") == 0)
352 : errtype = CTMSG_CSLIB;
353 : else {
354 0 : fprintf(stderr, "Unknown error type %s\n", errtype_str);
355 0 : exit(1);
356 : }
357 :
358 190 : number = strtol(strtok(NULL, " \t\n"), NULL, 0);
359 190 : message = strtok(NULL, "\n");
360 190 : check_last_message(errtype, number, message);
361 : }
362 :
363 : static void
364 1162 : do_bind(CS_BLKDESC *blkdesc, int colnum, CS_INT host_format, CS_INT host_type, CS_INT host_maxlen,
365 : void *var_addr, CS_INT *var_len_addr, CS_SMALLINT *var_ind_addr)
366 : {
367 : CS_DATAFMT datafmt;
368 :
369 1162 : check_call(blk_describe, (blkdesc, colnum, &datafmt));
370 :
371 1162 : datafmt.format = host_format;
372 1162 : datafmt.datatype = host_type;
373 1162 : datafmt.maxlength = host_maxlen;
374 1162 : datafmt.count = 1;
375 :
376 1162 : check_call(blk_bind, (blkdesc, colnum, &datafmt, var_addr, var_len_addr, var_ind_addr ));
377 1162 : }
378 :
379 : static const char table_name[] = "all_types_bcp_unittest";
380 :
381 10 : TEST_MAIN()
382 : {
383 : CS_CONNECTION *conn;
384 : CS_COMMAND *cmd;
385 10 : bool verbose = false;
386 : FILE *in;
387 : part_t part;
388 :
389 10 : printf("%s: Retrieve data using array binding \n", __FILE__);
390 : if (verbose) {
391 : printf("Trying login\n");
392 : }
393 10 : in = open_test_file(argc > 1 ? argv[1] : NULL);
394 10 : check_call(try_ctlogin, (&ctx, &conn, &cmd, verbose));
395 :
396 10 : check_call(cs_config, (ctx, CS_SET, CS_MESSAGE_CB, (CS_VOID *) cslibmsg_cb, CS_UNUSED, NULL));
397 10 : check_call(ct_callback, (NULL, conn, CS_SET, CS_CLIENTMSG_CB, (CS_VOID *) clientmsg_cb2));
398 :
399 : for (;;) {
400 310 : part = read_part_type(in);
401 160 : if (part == PART_END)
402 : break;
403 150 : assert(part == PART_SQL);
404 :
405 150 : single_test(conn, cmd, in);
406 : }
407 :
408 10 : printf("done\n");
409 :
410 10 : check_call(try_ctlogout, (ctx, conn, cmd, verbose));
411 10 : fclose(in);
412 :
413 10 : return 0;
414 : }
415 :
416 : static void
417 150 : single_test(CS_CONNECTION *conn, CS_COMMAND *cmd, FILE *in)
418 : {
419 : char command[512];
420 150 : char *create_table_sql, *out1, *out2, *select = NULL;
421 : CS_BLKDESC *blkdesc;
422 150 : int count = 0;
423 : int i;
424 : part_t part;
425 : CS_RETCODE ret;
426 150 : bool rows_sent = false;
427 :
428 150 : sprintf(command, "if exists (select 1 from sysobjects where type = 'U' and name = '%s') drop table %s",
429 : table_name, table_name);
430 :
431 150 : check_call(run_command, (cmd, command));
432 :
433 150 : create_table_sql = read_part(in);
434 150 : ret = run_command(cmd, create_table_sql);
435 150 : free(create_table_sql);
436 :
437 : /* on error skip the test */
438 150 : if (ret != CS_SUCCEED) {
439 48 : part = read_part_type(in);
440 48 : assert(part == PART_BIND);
441 48 : free(read_part(in));
442 :
443 48 : part = read_part_type(in);
444 48 : if (part == PART_SELECT) {
445 40 : free(read_part(in));
446 40 : part = read_part_type(in);
447 : }
448 48 : assert(part == PART_OUTPUT);
449 48 : free(read_part(in));
450 48 : return;
451 : }
452 :
453 102 : sprintf(command, "delete from %s", table_name);
454 102 : check_call(run_command, (cmd, command));
455 :
456 102 : check_call(blk_alloc, (conn, BLK_VERSION_150, &blkdesc));
457 :
458 102 : check_call(blk_init, (blkdesc, CS_BLK_IN, (char *) table_name, CS_NULLTERM));
459 :
460 102 : part = read_part_type(in);
461 102 : assert(part == PART_BIND);
462 :
463 102 : do_binds(blkdesc, in, &rows_sent);
464 :
465 102 : part = read_part_type(in);
466 102 : if (part == PART_SELECT) {
467 60 : select = read_part(in);
468 60 : part = read_part_type(in);
469 : }
470 102 : assert(part == PART_OUTPUT);
471 :
472 102 : if (!rows_sent) {
473 26 : printf("Sending same row 10 times... \n");
474 286 : for (i = 0; i < 10; i++)
475 260 : check_call(blk_rowxfer, (blkdesc));
476 : } else {
477 76 : check_call(blk_rowxfer, (blkdesc));
478 : }
479 :
480 102 : check_call(blk_done, (blkdesc, CS_BLK_ALL, &count));
481 :
482 102 : blk_drop(blkdesc);
483 :
484 102 : free_dynamic_bounded();
485 :
486 102 : printf("%d rows copied.\n", count);
487 :
488 102 : out1 = read_part(in);
489 102 : out2 = get_output(cmd, !rows_sent, select);
490 102 : free(select);
491 102 : if (strcmp(out1, out2) != 0) {
492 0 : fprintf(stderr, "Wrong output\n-- expected --\n%s\n-- got --\n%s\n--\n", out1, out2);
493 0 : exit(1);
494 : }
495 102 : free(out1);
496 102 : free(out2);
497 : }
498 :
499 : static char *
500 102 : get_output(CS_COMMAND *cmd, bool distinct, const char *select)
501 : {
502 : char command[512];
503 :
504 : CS_RETCODE ret;
505 : CS_RETCODE results_ret;
506 : CS_DATAFMT datafmt;
507 : CS_INT datalength;
508 102 : CS_SMALLINT *inds = NULL;
509 102 : CS_INT count, row_count = 0;
510 : CS_INT result_type;
511 102 : CS_CHAR *data = NULL;
512 : CS_INT num_cols;
513 : CS_INT i;
514 102 : char *out = strdup("");
515 :
516 102 : assert(out != NULL);
517 :
518 102 : if (select) {
519 60 : check_call(ct_command, (cmd, CS_LANG_CMD, (CS_CHAR *) select, CS_NULLTERM, CS_UNUSED));
520 : } else {
521 42 : sprintf(command, "select%s * from %s", distinct ? " distinct" : "", table_name);
522 42 : check_call(ct_command, (cmd, CS_LANG_CMD, command, CS_NULLTERM, CS_UNUSED));
523 : }
524 :
525 102 : check_call(ct_send, (cmd));
526 102 : while ((results_ret = ct_results(cmd, &result_type)) == CS_SUCCEED) {
527 204 : switch ((int) result_type) {
528 : case CS_CMD_SUCCEED:
529 : break;
530 : case CS_CMD_DONE:
531 : break;
532 0 : case CS_CMD_FAIL:
533 0 : fprintf(stderr, "ct_results() result_type CS_CMD_FAIL.\n");
534 0 : exit(1);
535 102 : case CS_ROW_RESULT:
536 102 : check_call(ct_res_info, (cmd, CS_NUMDATA, &num_cols, CS_UNUSED, NULL));
537 102 : data = malloc(num_cols * 256);
538 102 : assert(data != NULL);
539 102 : inds = calloc(num_cols, sizeof(*inds));
540 102 : assert(inds != NULL);
541 558 : for (i = 0; i < num_cols; i++) {
542 558 : datafmt.datatype = CS_CHAR_TYPE;
543 558 : datafmt.format = CS_FMT_NULLTERM;
544 558 : datafmt.maxlength = 256;
545 558 : datafmt.count = 1;
546 558 : datafmt.locale = NULL;
547 558 : check_call(ct_bind, (cmd, i + 1, &datafmt, data + 256 * i, &datalength, &inds[i]));
548 : }
549 :
550 416 : while ((ret = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count)) == CS_SUCCEED) {
551 314 : row_count += count;
552 1362 : for (i = 0; i < num_cols; i++) {
553 1048 : if (!inds[i])
554 892 : out = append_string(out, data + 256 * i);
555 : else
556 156 : out = append_string(out, "NULL");
557 1048 : out = append_string(out, "\n");
558 : }
559 : }
560 102 : switch ((int) ret) {
561 : case CS_END_DATA:
562 : break;
563 0 : case CS_FAIL:
564 0 : fprintf(stderr, "ct_fetch() returned CS_FAIL.\n");
565 0 : exit(1);
566 0 : case CS_ROW_FAIL:
567 0 : fprintf(stderr, "ct_fetch() CS_ROW_FAIL on row %d.\n", row_count);
568 0 : exit(1);
569 0 : default:
570 0 : fprintf(stderr, "ct_fetch() unexpected return.\n");
571 0 : exit(1);
572 : }
573 : break;
574 0 : case CS_COMPUTE_RESULT:
575 0 : fprintf(stderr, "ct_results() unexpected CS_COMPUTE_RESULT.\n");
576 0 : exit(1);
577 0 : default:
578 0 : fprintf(stderr, "ct_results() unexpected result_type.\n");
579 0 : exit(1);
580 : }
581 : }
582 102 : switch ((int) results_ret) {
583 : case CS_END_RESULTS:
584 : break;
585 0 : case CS_FAIL:
586 0 : fprintf(stderr, "ct_results() failed.\n");
587 0 : exit(1);
588 : break;
589 0 : default:
590 0 : fprintf(stderr, "ct_results() unexpected return.\n");
591 0 : exit(1);
592 : }
593 :
594 102 : free(data);
595 102 : free(inds);
596 102 : return out;
597 : }
598 :
599 :
600 : static FILE *
601 10 : open_test_file(const char *filename)
602 : {
603 10 : FILE *input_file = NULL;
604 : char in_file[256];
605 :
606 : /* If no filename requested, try blk_in.in in both the expected location and the current directory. */
607 10 : if (filename)
608 0 : input_file = fopen(filename, "r");
609 : else {
610 10 : snprintf(in_file, sizeof(in_file), "%s/blk_in.in", FREETDS_SRCDIR);
611 10 : filename = in_file;
612 10 : input_file = fopen(filename, "r");
613 10 : if (!input_file) {
614 0 : filename = "blk_in.in";
615 0 : input_file = fopen(filename, "r");
616 : }
617 : }
618 10 : if (!input_file) {
619 0 : fprintf(stderr, "could not open %s\n", filename);
620 0 : exit(1);
621 : }
622 10 : return input_file;
623 : }
624 :
625 : static part_t
626 560 : read_part_type(FILE *in)
627 : {
628 : char line[1024];
629 : part_t part;
630 :
631 560 : read_line(line, sizeof(line), in);
632 560 : if (strncmp(line, "end", 3) == 0)
633 : return PART_END;
634 :
635 550 : if (strcmp(line, "sql\n") == 0)
636 : part = PART_SQL;
637 400 : else if (strcmp(line, "bind\n") == 0)
638 : part = PART_BIND;
639 250 : else if (strcmp(line, "output\n") == 0)
640 : part = PART_OUTPUT;
641 100 : else if (strcmp(line, "select\n") == 0)
642 : part = PART_SELECT;
643 : else {
644 0 : fprintf(stderr, "Invalid part: %s\n", line);
645 0 : exit(1);
646 : }
647 550 : read_line(line, sizeof(line), in);
648 550 : if (strcmp(line, "--\n") != 0) {
649 0 : fprintf(stderr, "Error reading line\n");
650 0 : exit(1);
651 : }
652 : return part;
653 : }
654 :
655 : static char *
656 448 : read_part(FILE *in)
657 : {
658 : char line[1024];
659 448 : char *part = strdup("");
660 :
661 448 : assert(part != NULL);
662 : for (;;) {
663 6416 : read_line(line, sizeof(line), in);
664 6864 : if (strcmp(line, "--\n") == 0)
665 448 : return part;
666 6416 : part = append_string(part, line);
667 : }
668 : }
669 :
670 : static void
671 9730 : read_line(char *buf, size_t buf_len, FILE *f)
672 : {
673 9730 : if (fgets(buf, buf_len, f) == NULL || ferror(f)) {
674 0 : fprintf(stderr, "Error reading line\n");
675 0 : exit(1);
676 : }
677 9730 : }
678 :
679 : static char *
680 8512 : append_string(char *s1, const char *s2)
681 : {
682 8512 : assert(s1);
683 8512 : assert(s2);
684 8512 : s1 = realloc(s1, strlen(s1) + strlen(s2) + 1);
685 8512 : assert(s1 != NULL);
686 8512 : strcat(s1, s2);
687 8512 : return s1;
688 : }
|