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