LCOV - code coverage report
Current view: top level - src/ctlib/unittests - blk_in.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 218 263 82.9 %
Date: 2026-05-04 13:14:38 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.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, &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          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             : }

Generated by: LCOV version 1.13