LCOV - code coverage report
Current view: top level - src/ctlib/unittests - blk_in.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 153 195 78.5 %
Date: 2025-02-21 09:36:06 Functions: 11 11 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 CS_RETCODE
      12             : do_bind(CS_BLKDESC * blkdesc, int colnum, CS_INT host_format, CS_INT host_type, CS_INT host_maxlen,
      13             :         void        *var_addr,
      14             :         CS_INT      *var_len_addr,
      15             :         CS_SMALLINT *var_ind_addr );
      16             : static void do_one_bind(CS_BLKDESC * blkdesc, int col, const char *name);
      17             : static FILE *open_test_file(void);
      18             : typedef enum
      19             : {
      20             :         PART_END,
      21             :         PART_SQL,
      22             :         PART_BIND,
      23             :         PART_OUTPUT,
      24             : } part_t;
      25             : static part_t read_part_type(FILE * in);
      26             : static char *read_part(FILE * in);
      27             : static void read_line(char *buf, size_t buf_len, FILE * f);
      28             : static char *append_string(char *s1, const char *s2);
      29             : static char *get_output(CS_COMMAND * cmd);
      30             : static void single_test(CS_CONNECTION * conn, CS_COMMAND * cmd, FILE * in);
      31             : 
      32             : /*
      33             :  * Static data for insertion
      34             :  */
      35             : static int  not_null_bit = 1;
      36             : static CS_INT      l_not_null_bit = 4;
      37             : static CS_SMALLINT i_not_null_bit = 0;
      38             : 
      39             : static char not_null_char[] = "a char";
      40             : static CS_INT      l_not_null_char = 6;
      41             : static CS_SMALLINT i_not_null_char = 0;
      42             : 
      43             : static char not_null_varchar[] = "a varchar";
      44             : static CS_INT      l_not_null_varchar = 9;
      45             : static CS_SMALLINT i_not_null_varchar = 0;
      46             : 
      47             : static char not_null_datetime[] = "Dec 17 2003  3:44PM";
      48             : static CS_INT      l_not_null_datetime = 19;
      49             : static CS_SMALLINT i_not_null_datetime = 0;
      50             : 
      51             : static char not_null_smalldatetime[] = "Dec 17 2003  3:44PM";
      52             : static CS_INT      l_not_null_smalldatetime = 19;
      53             : static CS_SMALLINT i_not_null_smalldatetime = 0;
      54             : 
      55             : static char not_null_money[] = "12.34";
      56             : static CS_INT      l_not_null_money = 5;
      57             : static CS_SMALLINT i_not_null_money = 0;
      58             : 
      59             : static char not_null_smallmoney[] = "12.34";
      60             : static CS_INT      l_not_null_smallmoney = 5;
      61             : static CS_SMALLINT i_not_null_smallmoney = 0;
      62             : 
      63             : static char not_null_float[] = "12.34";
      64             : static CS_INT      l_not_null_float = 5;
      65             : static CS_SMALLINT i_not_null_float = 0;
      66             : 
      67             : static char not_null_real[] = "12.34";
      68             : static CS_INT      l_not_null_real = 5;
      69             : static CS_SMALLINT i_not_null_real = 0;
      70             : 
      71             : static char not_null_decimal[] = "12.34";
      72             : static CS_INT      l_not_null_decimal = 5;
      73             : static CS_SMALLINT i_not_null_decimal = 0;
      74             : 
      75             : static char not_null_numeric[] = "12.34";
      76             : static CS_INT      l_not_null_numeric = 5;
      77             : static CS_SMALLINT i_not_null_numeric = 0;
      78             : 
      79             : static int  not_null_int        = 1234;
      80             : static CS_INT      l_not_null_int = 4;
      81             : static CS_SMALLINT i_not_null_int = 0;
      82             : 
      83             : static int  not_null_smallint   = 1234;
      84             : static CS_INT      l_not_null_smallint = 4;
      85             : static CS_SMALLINT i_not_null_smallint = 0;
      86             : 
      87             : static int  not_null_tinyint    = 123;
      88             : static CS_INT      l_not_null_tinyint = 4;
      89             : static CS_SMALLINT i_not_null_tinyint = 0;
      90             : 
      91             : static CS_INT      l_null_char = 0;
      92             : static CS_SMALLINT i_null_char = -1;
      93             : 
      94             : static CS_INT      l_null_varchar = 0;
      95             : static CS_SMALLINT i_null_varchar = -1;
      96             : 
      97             : static CS_INT      l_null_datetime = 0;
      98             : static CS_SMALLINT i_null_datetime = -1;
      99             : 
     100             : static CS_INT      l_null_smalldatetime = 0;
     101             : static CS_SMALLINT i_null_smalldatetime = -1;
     102             : 
     103             : static CS_INT      l_null_money = 0;
     104             : static CS_SMALLINT i_null_money = -1;
     105             : 
     106             : static CS_INT      l_null_smallmoney = 0;
     107             : static CS_SMALLINT i_null_smallmoney = -1;
     108             : 
     109             : static CS_INT      l_null_float = 0;
     110             : static CS_SMALLINT i_null_float = -1;
     111             : 
     112             : static CS_INT      l_null_real = 0;
     113             : static CS_SMALLINT i_null_real = -1;
     114             : 
     115             : static CS_INT      l_null_decimal = 0;
     116             : static CS_SMALLINT i_null_decimal = -1;
     117             : 
     118             : static CS_INT      l_null_numeric = 0;
     119             : static CS_SMALLINT i_null_numeric = -1;
     120             : 
     121             : static CS_INT      l_null_int = 0;
     122             : static CS_SMALLINT i_null_int = -1;
     123             : 
     124             : static CS_INT      l_null_smallint = 0;
     125             : static CS_SMALLINT i_null_smallint = -1;
     126             : 
     127             : static CS_INT      l_null_tinyint = 0;
     128             : static CS_SMALLINT i_null_tinyint = -1;
     129             : 
     130             : static char not_null_varbinary[] = "123456789";
     131             : static CS_INT      l_not_null_varbinary = 9;
     132             : static CS_SMALLINT i_not_null_varbinary = 0;
     133             : 
     134             : static void
     135          20 : do_binds(CS_BLKDESC *blkdesc, FILE *in)
     136             : {
     137             :         char line[1024];
     138          20 :         int col = 1;
     139             : 
     140             :         for (;;) {
     141         580 :                 read_line(line, sizeof(line), in);
     142         300 :                 if (strcmp(line, "--\n") == 0)
     143          20 :                         return;
     144         280 :                 strtok(line, "\n");
     145         280 :                 do_one_bind(blkdesc, col, line);
     146         280 :                 ++col;
     147             :         }
     148             : }
     149             : 
     150             : static void
     151         280 : do_one_bind(CS_BLKDESC *blkdesc, int col, const char *name)
     152             : {
     153             : #define do_bind(bind_name, fmt, type, len, value) do { \
     154             :         if (strcmp(#bind_name, name) == 0) { \
     155             :                 do_bind(blkdesc, col, fmt, type, len, value, &l_ ## bind_name, &i_ ## bind_name); \
     156             :                 return; \
     157             :         } \
     158             : } while(0)
     159             : 
     160             :         /* non nulls */
     161             : 
     162         280 :         do_bind(not_null_bit, CS_FMT_UNUSED, CS_INT_TYPE, 4, &not_null_bit);
     163         270 :         do_bind(not_null_char, CS_FMT_NULLTERM, CS_CHAR_TYPE, 7, not_null_char);
     164         260 :         do_bind(not_null_varchar, CS_FMT_NULLTERM, CS_CHAR_TYPE, 10, not_null_varchar);
     165         250 :         do_bind(not_null_datetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_datetime);
     166         240 :         do_bind(not_null_smalldatetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_smalldatetime);
     167         230 :         do_bind(not_null_money, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_money);
     168         220 :         do_bind(not_null_smallmoney, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_smallmoney);
     169         210 :         do_bind(not_null_float, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_float);
     170         200 :         do_bind(not_null_real, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_real);
     171         190 :         do_bind(not_null_decimal, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_decimal);
     172         180 :         do_bind(not_null_numeric, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_numeric);
     173         170 :         do_bind(not_null_int, CS_FMT_UNUSED, CS_INT_TYPE, 4, &not_null_int);
     174         160 :         do_bind(not_null_smallint, CS_FMT_UNUSED, CS_INT_TYPE, 4, &not_null_smallint);
     175         150 :         do_bind(not_null_tinyint, CS_FMT_UNUSED, CS_INT_TYPE, 4, &not_null_tinyint);
     176         140 :         do_bind(not_null_varbinary, CS_FMT_NULLTERM, CS_BINARY_TYPE, 10, not_null_varbinary);
     177             : 
     178             :         /* nulls */
     179             : 
     180         130 :         do_bind(null_char, CS_FMT_NULLTERM, CS_CHAR_TYPE, 7, not_null_char);
     181         120 :         do_bind(null_varchar, CS_FMT_NULLTERM, CS_CHAR_TYPE, 10, not_null_varchar);
     182         110 :         do_bind(null_datetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_datetime);
     183         100 :         do_bind(null_smalldatetime, CS_FMT_NULLTERM, CS_CHAR_TYPE, 20, not_null_smalldatetime);
     184          90 :         do_bind(null_money, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_money);
     185          80 :         do_bind(null_smallmoney, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_smallmoney);
     186          70 :         do_bind(null_float, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_float);
     187          60 :         do_bind(null_real, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_real);
     188          50 :         do_bind(null_decimal, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_decimal);
     189          40 :         do_bind(null_numeric, CS_FMT_NULLTERM, CS_CHAR_TYPE, 6, not_null_numeric);
     190          30 :         do_bind(null_int, CS_FMT_UNUSED, CS_INT_TYPE, 4, &not_null_int);
     191          20 :         do_bind(null_smallint, CS_FMT_UNUSED, CS_INT_TYPE, 4, &not_null_smallint);
     192          10 :         do_bind(null_tinyint, CS_FMT_UNUSED, CS_INT_TYPE, 4, &not_null_tinyint);
     193             : #undef do_bind
     194             : 
     195           0 :         fprintf(stderr, "Column %s not found\n", name);
     196           0 :         exit(1);
     197             : }
     198             : 
     199             : static CS_RETCODE
     200         280 : do_bind(CS_BLKDESC * blkdesc, int colnum, CS_INT host_format, CS_INT host_type, CS_INT host_maxlen,
     201             :         void        *var_addr,
     202             :         CS_INT      *var_len_addr,
     203             :         CS_SMALLINT *var_ind_addr )
     204             : {
     205             :         CS_DATAFMT datafmt;
     206             :         CS_RETCODE ret;
     207             : 
     208         280 :         ret = blk_describe(blkdesc, colnum, &datafmt);
     209         280 :         if (ret != CS_SUCCEED) {
     210           0 :                 fprintf(stderr, "blk_describe(%d) failed", colnum);
     211           0 :                 return ret;
     212             :         }
     213             : 
     214         280 :         datafmt.format = host_format;
     215         280 :         datafmt.datatype = host_type;
     216         280 :         datafmt.maxlength = host_maxlen;
     217         280 :         datafmt.count = 1;
     218             : 
     219         280 :         ret = blk_bind(blkdesc, colnum, &datafmt, var_addr, var_len_addr, var_ind_addr );
     220         280 :         if (ret != CS_SUCCEED) {
     221           0 :                 fprintf(stderr, "blk_bind() failed\n");
     222           0 :                 return ret;
     223             :         }
     224             :         return ret;
     225             : }
     226             : 
     227             : static const char table_name[] = "all_types_bcp_unittest";
     228             : 
     229             : int
     230          10 : main(void)
     231             : {
     232             :         CS_CONTEXT *ctx;
     233             :         CS_CONNECTION *conn;
     234             :         CS_COMMAND *cmd;
     235          10 :         int verbose = 0;
     236             :         FILE *in;
     237             :         part_t part;
     238             : 
     239          10 :         printf("%s: Retrieve data using array binding \n", __FILE__);
     240             :         if (verbose) {
     241             :                 printf("Trying login\n");
     242             :         }
     243          10 :         in = open_test_file();
     244          10 :         check_call(try_ctlogin, (&ctx, &conn, &cmd, verbose));
     245             : 
     246             :         for (;;) {
     247          50 :                 part = read_part_type(in);
     248          30 :                 if (part == PART_END)
     249             :                         break;
     250          20 :                 assert(part == PART_SQL);
     251             : 
     252          20 :                 single_test(conn, cmd, in);
     253             :         }
     254             : 
     255          10 :         printf("done\n");
     256             : 
     257          10 :         check_call(try_ctlogout, (ctx, conn, cmd, verbose));
     258          10 :         fclose(in);
     259             : 
     260             :         return 0;
     261             : }
     262             : 
     263             : static void
     264          20 : single_test(CS_CONNECTION *conn, CS_COMMAND *cmd, FILE *in)
     265             : {
     266             :         char command[512];
     267             :         char *create_table_sql, *out1, *out2;
     268             :         CS_BLKDESC *blkdesc;
     269          20 :         int count = 0;
     270             :         int i;
     271             :         part_t part;
     272             : 
     273          20 :         sprintf(command, "if exists (select 1 from sysobjects where type = 'U' and name = '%s') drop table %s",
     274             :                 table_name, table_name);
     275             : 
     276          20 :         check_call(run_command, (cmd, command));
     277             : 
     278          20 :         create_table_sql = read_part(in);
     279          20 :         check_call(run_command, (cmd, create_table_sql));
     280          20 :         free(create_table_sql);
     281             : 
     282          20 :         sprintf(command, "delete from %s", table_name);
     283          20 :         check_call(run_command, (cmd, command));
     284             : 
     285          20 :         check_call(blk_alloc, (conn, BLK_VERSION_100, &blkdesc));
     286             : 
     287          20 :         check_call(blk_init, (blkdesc, CS_BLK_IN, (char *) table_name, CS_NULLTERM));
     288             : 
     289          20 :         part = read_part_type(in);
     290          20 :         assert(part == PART_BIND);
     291             : 
     292          20 :         do_binds(blkdesc, in);
     293             : 
     294          20 :         part = read_part_type(in);
     295          20 :         assert(part == PART_OUTPUT);
     296             : 
     297          20 :         printf("Sending same row 10 times... \n");
     298         220 :         for (i = 0; i < 10; i++) {
     299         200 :                 check_call(blk_rowxfer, (blkdesc));
     300             :         }
     301             : 
     302          20 :         check_call(blk_done, (blkdesc, CS_BLK_ALL, &count));
     303             : 
     304          20 :         blk_drop(blkdesc);
     305             : 
     306          20 :         printf("%d rows copied.\n", count);
     307             : 
     308          20 :         out1 = read_part(in);
     309          20 :         out2 = get_output(cmd);
     310          20 :         if (strcmp(out1, out2) != 0) {
     311           0 :                 fprintf(stderr, "Wrong output\n--\n%s\n--\n%s\n--\n", out1, out2);
     312           0 :                 exit(1);
     313             :         }
     314          20 :         free(out1);
     315          20 :         free(out2);
     316          20 : }
     317             : 
     318             : static char *
     319          20 : get_output(CS_COMMAND *cmd)
     320             : {
     321             :         char command[512];
     322             : 
     323             :         CS_RETCODE ret;
     324             :         CS_RETCODE results_ret;
     325             :         CS_DATAFMT datafmt;
     326             :         CS_INT datalength;
     327          20 :         CS_SMALLINT *inds = NULL;
     328          20 :         CS_INT count, row_count = 0;
     329             :         CS_INT result_type;
     330          20 :         CS_CHAR *data = NULL;
     331             :         CS_INT num_cols;
     332             :         CS_INT i;
     333          20 :         char *out = strdup("");
     334             : 
     335          20 :         assert(out != NULL);
     336             : 
     337          20 :         sprintf(command, "select distinct * from %s", table_name);
     338          20 :         check_call(ct_command, (cmd, CS_LANG_CMD, command, CS_NULLTERM, CS_UNUSED));
     339             : 
     340          20 :         check_call(ct_send, (cmd));
     341          20 :         while ((results_ret = ct_results(cmd, &result_type)) == CS_SUCCEED) {
     342          40 :                 switch ((int) result_type) {
     343             :                 case CS_CMD_SUCCEED:
     344             :                         break;
     345             :                 case CS_CMD_DONE:
     346             :                         break;
     347           0 :                 case CS_CMD_FAIL:
     348           0 :                         fprintf(stderr, "ct_results() result_type CS_CMD_FAIL.\n");
     349           0 :                         exit(1);
     350          20 :                 case CS_ROW_RESULT:
     351          20 :                         check_call(ct_res_info, (cmd, CS_NUMDATA, &num_cols, CS_UNUSED, NULL));
     352          20 :                         data = malloc(num_cols * 256);
     353          20 :                         assert(data != NULL);
     354          20 :                         inds = calloc(num_cols, sizeof(*inds));
     355          20 :                         assert(inds != NULL);
     356         280 :                         for (i = 0; i < num_cols; i++) {
     357         280 :                                 datafmt.datatype = CS_CHAR_TYPE;
     358         280 :                                 datafmt.format = CS_FMT_NULLTERM;
     359         280 :                                 datafmt.maxlength = 256;
     360         280 :                                 datafmt.count = 1;
     361         280 :                                 datafmt.locale = NULL;
     362         280 :                                 check_call(ct_bind, (cmd, i + 1, &datafmt, data + 256 * i, &datalength, &inds[i]));
     363             :                         }
     364             : 
     365          40 :                         while ((ret = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count)) == CS_SUCCEED) {
     366          20 :                                 row_count += count;
     367         300 :                                 for (i = 0; i < num_cols; i++) {
     368         280 :                                         if (!inds[i])
     369         150 :                                                 out = append_string(out, data + 256 * i);
     370             :                                         else
     371         130 :                                                 out = append_string(out, "NULL");
     372         280 :                                         out = append_string(out, "\n");
     373             :                                 }
     374             :                         }
     375          20 :                         switch ((int) ret) {
     376             :                         case CS_END_DATA:
     377             :                                 break;
     378           0 :                         case CS_FAIL:
     379           0 :                                 fprintf(stderr, "ct_fetch() returned CS_FAIL.\n");
     380           0 :                                 exit(1);
     381           0 :                         case CS_ROW_FAIL:
     382           0 :                                 fprintf(stderr, "ct_fetch() CS_ROW_FAIL on row %d.\n", row_count);
     383           0 :                                 exit(1);
     384           0 :                         default:
     385           0 :                                 fprintf(stderr, "ct_fetch() unexpected return.\n");
     386           0 :                                 exit(1);
     387             :                         }
     388             :                         break;
     389           0 :                 case CS_COMPUTE_RESULT:
     390           0 :                         fprintf(stderr, "ct_results() unexpected CS_COMPUTE_RESULT.\n");
     391           0 :                         exit(1);
     392           0 :                 default:
     393           0 :                         fprintf(stderr, "ct_results() unexpected result_type.\n");
     394           0 :                         exit(1);
     395             :                 }
     396             :         }
     397          20 :         switch ((int) results_ret) {
     398             :         case CS_END_RESULTS:
     399             :                 break;
     400           0 :         case CS_FAIL:
     401           0 :                 fprintf(stderr, "ct_results() failed.\n");
     402           0 :                 exit(1);
     403             :                 break;
     404           0 :         default:
     405           0 :                 fprintf(stderr, "ct_results() unexpected return.\n");
     406           0 :                 exit(1);
     407             :         }
     408             : 
     409          20 :         free(data);
     410          20 :         free(inds);
     411          20 :         return out;
     412             : }
     413             : 
     414             : 
     415             : static FILE *
     416          10 : open_test_file(void)
     417             : {
     418             :         FILE *input_file;
     419             :         char in_file[256];
     420             : 
     421          10 :         snprintf(in_file, sizeof(in_file), "%s/blk_in.in", FREETDS_SRCDIR);
     422             : 
     423          10 :         input_file = fopen(in_file, "r");
     424          10 :         if (!input_file) {
     425           0 :                 strcpy(in_file, "blk_in.in");
     426           0 :                 input_file = fopen(in_file, "r");
     427             :         }
     428          10 :         if (!input_file) {
     429           0 :                 fprintf(stderr, "could not open %s\n", in_file);
     430           0 :                 exit(1);
     431             :         }
     432          10 :         return input_file;
     433             : }
     434             : 
     435             : static part_t
     436          70 : read_part_type(FILE *in)
     437             : {
     438             :         char line[1024];
     439             :         part_t part;
     440             : 
     441          70 :         read_line(line, sizeof(line), in);
     442          70 :         if (strncmp(line, "end", 3) == 0)
     443             :                 return PART_END;
     444             : 
     445          60 :         if (strcmp(line, "sql\n") == 0)
     446             :                 part = PART_SQL;
     447          40 :         else if (strcmp(line, "bind\n") == 0)
     448             :                 part = PART_BIND;
     449          20 :         else if (strcmp(line, "output\n") == 0)
     450             :                 part = PART_OUTPUT;
     451             :         else {
     452           0 :                 fprintf(stderr, "Invalid part: %s\n", line);
     453           0 :                 exit(1);
     454             :         }
     455          60 :         read_line(line, sizeof(line), in);
     456          60 :         if (strcmp(line, "--\n") != 0) {
     457           0 :                 fprintf(stderr, "Error reading line\n");
     458           0 :                 exit(1);
     459             :         }
     460             :         return part;
     461             : }
     462             : 
     463             : static char *
     464          40 : read_part(FILE *in)
     465             : {
     466             :         char line[1024];
     467          40 :         char *part = strdup("");
     468             : 
     469          40 :         assert(part != NULL);
     470             :         for (;;) {
     471        1700 :                 read_line(line, sizeof(line), in);
     472        1740 :                 if (strcmp(line, "--\n") == 0)
     473          40 :                         return part;
     474        1700 :                 part = append_string(part, line);
     475             :         }
     476             : }
     477             : 
     478             : static void
     479        2170 : read_line(char *buf, size_t buf_len, FILE *f)
     480             : {
     481        2170 :         if (fgets(buf, buf_len, f) == NULL || ferror(f)) {
     482           0 :                 fprintf(stderr, "Error reading line\n");
     483           0 :                 exit(1);
     484             :         }
     485        2170 : }
     486             : 
     487             : static char *
     488        2260 : append_string(char *s1, const char *s2)
     489             : {
     490        2260 :         assert(s1);
     491        2260 :         assert(s2);
     492        2260 :         s1 = realloc(s1, strlen(s1) + strlen(s2) + 1);
     493        2260 :         assert(s1 != NULL);
     494        2260 :         strcat(s1, s2);
     495        2260 :         return s1;
     496             : }

Generated by: LCOV version 1.13