LCOV - code coverage report
Current view: top level - src/ctlib/unittests - blk_in.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 211 261 80.8 %
Date: 2026-03-24 22:22:09 Functions: 14 14 100.0 %

          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.34";
      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          32 : do_binds(CS_BLKDESC *blkdesc, FILE *in, bool *rows_sent)
     137             : {
     138             :         char line[1024];
     139          32 :         int col = 1;
     140             : 
     141          32 :         *rows_sent = false;
     142             :         for (;;) {
     143             :                 const char *tok;
     144             : 
     145         446 :                 read_line(line, sizeof(line), in);
     146         446 :                 if (strcmp(line, "--\n") == 0)
     147          32 :                         return;
     148         414 :                 tok = strtok(line, " \t\n");
     149             : 
     150         414 :                 if (strcmp(tok, "--") == 0) {
     151             :                         /* comment */
     152          10 :                         continue;
     153         404 :                 } else if (strncmp(tok, "SENDROW", 7) == 0) {
     154          30 :                         sendrow(blkdesc, tok);
     155          30 :                         col = 0;
     156          30 :                         *rows_sent = true;
     157         374 :                 } else if (strncmp(tok, "CS_", 3) == 0) {
     158          40 :                         do_type_bind(blkdesc, col, tok);
     159             :                 } else {
     160         334 :                         do_one_bind(blkdesc, col, line);
     161             :                 }
     162         404 :                 ++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, &not_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, &not_null_int);
     190         190 :         do_bind(not_null_smallint, CS_FMT_UNUSED, CS_INT_TYPE, 4, &not_null_smallint);
     191         178 :         do_bind(not_null_tinyint, CS_FMT_UNUSED, CS_INT_TYPE, 4, &not_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, &not_null_int);
     207          24 :         do_bind(null_smallint, CS_FMT_UNUSED, CS_INT_TYPE, 4, &not_null_smallint);
     208          12 :         do_bind(null_tinyint, CS_FMT_UNUSED, CS_INT_TYPE, 4, &not_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          32 : free_dynamic_bounded(void)
     227             : {
     228         104 :         while (dynamic_bounded) {
     229          40 :                 bound_value *next = dynamic_bounded->next;
     230             : 
     231          40 :                 free(dynamic_bounded->value);
     232          40 :                 free(dynamic_bounded);
     233          40 :                 dynamic_bounded = next;
     234             :         }
     235          32 : }
     236             : 
     237             : static void
     238          40 : do_type_bind(CS_BLKDESC *blkdesc, int col, const char *tok)
     239             : {
     240          40 :         if (strcmp(tok, "CS_CHAR_TYPE") == 0) {
     241          80 :                 CS_INT maxlen = atoi(strtok(NULL, " \t\n"));
     242          40 :                 char *value = strdup(strtok(NULL, "\n"));
     243          40 :                 bound_value *bound = calloc(1, sizeof(*bound));
     244             : 
     245          40 :                 assert(value);
     246          40 :                 assert(bound);
     247             : 
     248          40 :                 if (strncmp(value, "\"\"\"", 3) == 0) {
     249             :                         char *p;
     250             : 
     251           0 :                         memmove(value, value + 3, strlen(value + 2));
     252           0 :                         p = strstr(value, "\"\"\"");
     253           0 :                         if (p)
     254           0 :                                 *p = '\0';
     255             :                 }
     256          40 :                 bound->varlen = strlen(value);
     257          40 :                 bound->ind = 0;
     258          40 :                 bound->value = value;
     259          40 :                 bound->next = dynamic_bounded;
     260          40 :                 dynamic_bounded = bound;
     261          40 :                 do_bind(blkdesc, col, CS_FMT_NULLTERM, CS_CHAR_TYPE, maxlen, value, &bound->varlen, &bound->ind);
     262             : 
     263          40 :                 return;
     264             :         }
     265           0 :         fprintf(stderr, "Unhandled type %s\n", tok);
     266           0 :         exit(1);
     267             : }
     268             : 
     269             : static void
     270          30 : 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          30 :         if (strcmp(tok, "SENDROWERROR") == 0) {
     278          20 :                 check_fail(blk_rowxfer, (blkdesc));
     279             :         } else {
     280          10 :                 ct_reset_last_message();
     281          10 :                 check_call(blk_rowxfer, (blkdesc));
     282             :         }
     283             : 
     284          30 :         errtype_str = strtok(NULL, " \t\n");
     285          30 :         if (!errtype_str) {
     286          10 :                 check_last_message(CTMSG_NONE, 0, NULL);
     287          10 :                 return;
     288             :         }
     289             : 
     290          20 :         if (strcmp(errtype_str, "CLIENT") == 0)
     291             :                 errtype = CTMSG_CLIENT;
     292           0 :         else if (strcmp(errtype_str, "CLIENT2") == 0)
     293             :                 errtype = CTMSG_CLIENT2;
     294           0 :         else if (strcmp(errtype_str, "SERVER") == 0)
     295             :                 errtype = CTMSG_SERVER;
     296           0 :         else if (strcmp(errtype_str, "CSLIB") == 0)
     297             :                 errtype = CTMSG_CSLIB;
     298             :         else {
     299           0 :                 fprintf(stderr, "Unknown error type %s\n", errtype_str);
     300           0 :                 exit(1);
     301             :         }
     302             : 
     303          20 :         number = strtol(strtok(NULL, " \t\n"), NULL, 0);
     304          20 :         message = strtok(NULL, "\n");
     305          20 :         check_last_message(errtype, number, message);
     306             : }
     307             : 
     308             : static void
     309         374 : do_bind(CS_BLKDESC *blkdesc, int colnum, CS_INT host_format, CS_INT host_type, CS_INT host_maxlen,
     310             :         void *var_addr, CS_INT *var_len_addr, CS_SMALLINT *var_ind_addr)
     311             : {
     312             :         CS_DATAFMT datafmt;
     313             : 
     314         374 :         check_call(blk_describe, (blkdesc, colnum, &datafmt));
     315             : 
     316         374 :         datafmt.format = host_format;
     317         374 :         datafmt.datatype = host_type;
     318         374 :         datafmt.maxlength = host_maxlen;
     319         374 :         datafmt.count = 1;
     320             : 
     321         374 :         check_call(blk_bind, (blkdesc, colnum, &datafmt, var_addr, var_len_addr, var_ind_addr ));
     322         374 : }
     323             : 
     324             : static const char table_name[] = "all_types_bcp_unittest";
     325             : 
     326          10 : TEST_MAIN()
     327             : {
     328             :         CS_CONTEXT *ctx;
     329             :         CS_CONNECTION *conn;
     330             :         CS_COMMAND *cmd;
     331          10 :         bool verbose = false;
     332             :         FILE *in;
     333             :         part_t part;
     334             : 
     335          10 :         printf("%s: Retrieve data using array binding \n", __FILE__);
     336             :         if (verbose) {
     337             :                 printf("Trying login\n");
     338             :         }
     339          10 :         in = open_test_file(argc > 1 ? argv[1] : NULL);
     340          10 :         check_call(try_ctlogin, (&ctx, &conn, &cmd, verbose));
     341             : 
     342             :         for (;;) {
     343          90 :                 part = read_part_type(in);
     344          50 :                 if (part == PART_END)
     345             :                         break;
     346          40 :                 assert(part == PART_SQL);
     347             : 
     348          40 :                 single_test(conn, cmd, in);
     349             :         }
     350             : 
     351          10 :         printf("done\n");
     352             : 
     353          10 :         check_call(try_ctlogout, (ctx, conn, cmd, verbose));
     354          10 :         fclose(in);
     355             : 
     356          10 :         return 0;
     357             : }
     358             : 
     359             : static void
     360          40 : single_test(CS_CONNECTION *conn, CS_COMMAND *cmd, FILE *in)
     361             : {
     362             :         char command[512];
     363             :         char *create_table_sql, *out1, *out2;
     364             :         CS_BLKDESC *blkdesc;
     365          40 :         int count = 0;
     366             :         int i;
     367             :         part_t part;
     368             :         CS_RETCODE ret;
     369          40 :         bool rows_sent = false;
     370             : 
     371          40 :         sprintf(command, "if exists (select 1 from sysobjects where type = 'U' and name = '%s') drop table %s",
     372             :                 table_name, table_name);
     373             : 
     374          40 :         check_call(run_command, (cmd, command));
     375             : 
     376          40 :         create_table_sql = read_part(in);
     377          40 :         ret = run_command(cmd, create_table_sql);
     378          40 :         free(create_table_sql);
     379             : 
     380             :         /* on error skip the test */
     381          40 :         if (ret != CS_SUCCEED) {
     382           8 :                 part = read_part_type(in);
     383           8 :                 assert(part == PART_BIND);
     384           8 :                 free(read_part(in));
     385             : 
     386           8 :                 part = read_part_type(in);
     387           8 :                 assert(part == PART_OUTPUT);
     388           8 :                 free(read_part(in));
     389           8 :                 return;
     390             :         }
     391             : 
     392          32 :         sprintf(command, "delete from %s", table_name);
     393          32 :         check_call(run_command, (cmd, command));
     394             : 
     395          32 :         check_call(blk_alloc, (conn, BLK_VERSION_150, &blkdesc));
     396             : 
     397          32 :         check_call(blk_init, (blkdesc, CS_BLK_IN, (char *) table_name, CS_NULLTERM));
     398             : 
     399          32 :         part = read_part_type(in);
     400          32 :         assert(part == PART_BIND);
     401             : 
     402          32 :         do_binds(blkdesc, in, &rows_sent);
     403             : 
     404          32 :         part = read_part_type(in);
     405          32 :         assert(part == PART_OUTPUT);
     406             : 
     407          32 :         if (!rows_sent) {
     408          22 :                 printf("Sending same row 10 times... \n");
     409         242 :                 for (i = 0; i < 10; i++)
     410         220 :                         check_call(blk_rowxfer, (blkdesc));
     411             :         } else {
     412          10 :                 check_call(blk_rowxfer, (blkdesc));
     413             :         }
     414             : 
     415          32 :         check_call(blk_done, (blkdesc, CS_BLK_ALL, &count));
     416             : 
     417          32 :         blk_drop(blkdesc);
     418             : 
     419          32 :         free_dynamic_bounded();
     420             : 
     421          32 :         printf("%d rows copied.\n", count);
     422             : 
     423          32 :         out1 = read_part(in);
     424          32 :         out2 = get_output(cmd, !rows_sent);
     425          32 :         if (strcmp(out1, out2) != 0) {
     426           0 :                 fprintf(stderr, "Wrong output\n-- expected --\n%s\n-- got --\n%s\n--\n", out1, out2);
     427           0 :                 exit(1);
     428             :         }
     429          32 :         free(out1);
     430          32 :         free(out2);
     431             : }
     432             : 
     433             : static char *
     434          32 : get_output(CS_COMMAND *cmd, bool distinct)
     435             : {
     436             :         char command[512];
     437             : 
     438             :         CS_RETCODE ret;
     439             :         CS_RETCODE results_ret;
     440             :         CS_DATAFMT datafmt;
     441             :         CS_INT datalength;
     442          32 :         CS_SMALLINT *inds = NULL;
     443          32 :         CS_INT count, row_count = 0;
     444             :         CS_INT result_type;
     445          32 :         CS_CHAR *data = NULL;
     446             :         CS_INT num_cols;
     447             :         CS_INT i;
     448          32 :         char *out = strdup("");
     449             : 
     450          32 :         assert(out != NULL);
     451             : 
     452          32 :         sprintf(command, "select%s * from %s", distinct ? " distinct" : "", table_name);
     453          32 :         check_call(ct_command, (cmd, CS_LANG_CMD, command, CS_NULLTERM, CS_UNUSED));
     454             : 
     455          32 :         check_call(ct_send, (cmd));
     456          32 :         while ((results_ret = ct_results(cmd, &result_type)) == CS_SUCCEED) {
     457          64 :                 switch ((int) result_type) {
     458             :                 case CS_CMD_SUCCEED:
     459             :                         break;
     460             :                 case CS_CMD_DONE:
     461             :                         break;
     462           0 :                 case CS_CMD_FAIL:
     463           0 :                         fprintf(stderr, "ct_results() result_type CS_CMD_FAIL.\n");
     464           0 :                         exit(1);
     465          32 :                 case CS_ROW_RESULT:
     466          32 :                         check_call(ct_res_info, (cmd, CS_NUMDATA, &num_cols, CS_UNUSED, NULL));
     467          32 :                         data = malloc(num_cols * 256);
     468          32 :                         assert(data != NULL);
     469          32 :                         inds = calloc(num_cols, sizeof(*inds));
     470          32 :                         assert(inds != NULL);
     471         344 :                         for (i = 0; i < num_cols; i++) {
     472         344 :                                 datafmt.datatype = CS_CHAR_TYPE;
     473         344 :                                 datafmt.format = CS_FMT_NULLTERM;
     474         344 :                                 datafmt.maxlength = 256;
     475         344 :                                 datafmt.count = 1;
     476         344 :                                 datafmt.locale = NULL;
     477         344 :                                 check_call(ct_bind, (cmd, i + 1, &datafmt, data + 256 * i, &datalength, &inds[i]));
     478             :                         }
     479             : 
     480          74 :                         while ((ret = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count)) == CS_SUCCEED) {
     481          42 :                                 row_count += count;
     482         396 :                                 for (i = 0; i < num_cols; i++) {
     483         354 :                                         if (!inds[i])
     484         198 :                                                 out = append_string(out, data + 256 * i);
     485             :                                         else
     486         156 :                                                 out = append_string(out, "NULL");
     487         354 :                                         out = append_string(out, "\n");
     488             :                                 }
     489             :                         }
     490          32 :                         switch ((int) ret) {
     491             :                         case CS_END_DATA:
     492             :                                 break;
     493           0 :                         case CS_FAIL:
     494           0 :                                 fprintf(stderr, "ct_fetch() returned CS_FAIL.\n");
     495           0 :                                 exit(1);
     496           0 :                         case CS_ROW_FAIL:
     497           0 :                                 fprintf(stderr, "ct_fetch() CS_ROW_FAIL on row %d.\n", row_count);
     498           0 :                                 exit(1);
     499           0 :                         default:
     500           0 :                                 fprintf(stderr, "ct_fetch() unexpected return.\n");
     501           0 :                                 exit(1);
     502             :                         }
     503             :                         break;
     504           0 :                 case CS_COMPUTE_RESULT:
     505           0 :                         fprintf(stderr, "ct_results() unexpected CS_COMPUTE_RESULT.\n");
     506           0 :                         exit(1);
     507           0 :                 default:
     508           0 :                         fprintf(stderr, "ct_results() unexpected result_type.\n");
     509           0 :                         exit(1);
     510             :                 }
     511             :         }
     512          32 :         switch ((int) results_ret) {
     513             :         case CS_END_RESULTS:
     514             :                 break;
     515           0 :         case CS_FAIL:
     516           0 :                 fprintf(stderr, "ct_results() failed.\n");
     517           0 :                 exit(1);
     518             :                 break;
     519           0 :         default:
     520           0 :                 fprintf(stderr, "ct_results() unexpected return.\n");
     521           0 :                 exit(1);
     522             :         }
     523             : 
     524          32 :         free(data);
     525          32 :         free(inds);
     526          32 :         return out;
     527             : }
     528             : 
     529             : 
     530             : static FILE *
     531          10 : open_test_file(const char *filename)
     532             : {
     533          10 :         FILE *input_file = NULL;
     534             :         char in_file[256];
     535             : 
     536             :         /* If no filename requested, try blk_in.in in both the expected location and the current directory. */
     537          10 :         if (filename)
     538           0 :                 input_file = fopen(filename, "r");
     539             :         else {
     540          10 :                 snprintf(in_file, sizeof(in_file), "%s/blk_in.in", FREETDS_SRCDIR);
     541          10 :                 filename = in_file;
     542          10 :                 input_file = fopen(filename, "r");
     543          10 :                 if (!input_file) {
     544           0 :                         filename = "blk_in.in";
     545           0 :                         input_file = fopen(filename, "r");
     546             :                 }
     547             :         }
     548          10 :         if (!input_file) {
     549           0 :                 fprintf(stderr, "could not open %s\n", filename);
     550           0 :                 exit(1);
     551             :         }
     552          10 :         return input_file;
     553             : }
     554             : 
     555             : static part_t
     556         130 : read_part_type(FILE *in)
     557             : {
     558             :         char line[1024];
     559             :         part_t part;
     560             : 
     561         130 :         read_line(line, sizeof(line), in);
     562         130 :         if (strncmp(line, "end", 3) == 0)
     563             :                 return PART_END;
     564             : 
     565         120 :         if (strcmp(line, "sql\n") == 0)
     566             :                 part = PART_SQL;
     567          80 :         else if (strcmp(line, "bind\n") == 0)
     568             :                 part = PART_BIND;
     569          40 :         else if (strcmp(line, "output\n") == 0)
     570             :                 part = PART_OUTPUT;
     571             :         else {
     572           0 :                 fprintf(stderr, "Invalid part: %s\n", line);
     573           0 :                 exit(1);
     574             :         }
     575         120 :         read_line(line, sizeof(line), in);
     576         120 :         if (strcmp(line, "--\n") != 0) {
     577           0 :                 fprintf(stderr, "Error reading line\n");
     578           0 :                 exit(1);
     579             :         }
     580             :         return part;
     581             : }
     582             : 
     583             : static char *
     584          88 : read_part(FILE *in)
     585             : {
     586             :         char line[1024];
     587          88 :         char *part = strdup("");
     588             : 
     589          88 :         assert(part != NULL);
     590             :         for (;;) {
     591        3636 :                 read_line(line, sizeof(line), in);
     592        3724 :                 if (strcmp(line, "--\n") == 0)
     593          88 :                         return part;
     594        3636 :                 part = append_string(part, line);
     595             :         }
     596             : }
     597             : 
     598             : static void
     599        4420 : read_line(char *buf, size_t buf_len, FILE *f)
     600             : {
     601        4420 :         if (fgets(buf, buf_len, f) == NULL || ferror(f)) {
     602           0 :                 fprintf(stderr, "Error reading line\n");
     603           0 :                 exit(1);
     604             :         }
     605        4420 : }
     606             : 
     607             : static char *
     608        4344 : append_string(char *s1, const char *s2)
     609             : {
     610        4344 :         assert(s1);
     611        4344 :         assert(s2);
     612        4344 :         s1 = realloc(s1, strlen(s1) + strlen(s2) + 1);
     613        4344 :         assert(s1 != NULL);
     614        4344 :         strcat(s1, s2);
     615        4344 :         return s1;
     616             : }

Generated by: LCOV version 1.13