LCOV - code coverage report
Current view: top level - src/dblib/unittests - t0016.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 174 209 83.3 %
Date: 2026-03-26 08:28:16 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /* 
       2             :  * Purpose: Test bcp in and out, and specifically bcp_colfmt()
       3             :  * Functions: bcp_colfmt bcp_columns bcp_exec bcp_init 
       4             :  */
       5             : 
       6             : #include "common.h"
       7             : 
       8             : #include <freetds/bool.h>
       9             : #include <freetds/replacements.h>
      10             : 
      11             : static bool failed = false;
      12             : 
      13             : static void
      14           0 : failure(const char *fmt, ...)
      15             : {
      16             :         va_list ap;
      17             : 
      18           0 :         failed = true;
      19             : 
      20           0 :         va_start(ap, fmt);
      21           0 :         vfprintf(stderr, fmt, ap);
      22           0 :         va_end(ap);
      23           0 : }
      24             : 
      25             : #define INFILE_NAME "t0016"
      26             : #define TABLE_NAME "#dblib0016"
      27             : 
      28             : static void test_file(const char *fn);
      29             : static bool compare_files(const char *fn1, const char *fn2);
      30             : static unsigned count_file_rows(FILE *f);
      31             : static size_t fgets_raw(char *s, int len, FILE * f);
      32             : static DBPROCESS *dbproc;
      33             : 
      34          10 : TEST_MAIN()
      35             : {
      36             :         LOGINREC *login;
      37             :         char in_file[30];
      38             :         unsigned int n;
      39             : 
      40          10 :         setbuf(stdout, NULL);
      41          10 :         setbuf(stderr, NULL);
      42             : 
      43          10 :         set_malloc_options();
      44             : 
      45          10 :         read_login_info(argc, argv);
      46          10 :         printf("Starting %s\n", argv[0]);
      47          10 :         dbsetversion(DBVERSION_100);
      48          10 :         dbinit();
      49             : 
      50          10 :         dberrhandle(syb_err_handler);
      51          10 :         dbmsghandle(syb_msg_handler);
      52             : 
      53          10 :         printf("About to logon\n");
      54             : 
      55          10 :         login = dblogin();
      56          10 :         BCP_SETL(login, TRUE);
      57          10 :         DBSETLPWD(login, PASSWORD);
      58          10 :         DBSETLUSER(login, USER);
      59          10 :         DBSETLAPP(login, "t0016");
      60          10 :         DBSETLCHARSET(login, "utf8");
      61             : 
      62          10 :         dbproc = dbopen(login, SERVER);
      63          10 :         if (strlen(DATABASE)) {
      64          10 :                 dbuse(dbproc, DATABASE);
      65             :         }
      66          10 :         dbloginfree(login);
      67          10 :         printf("After logon\n");
      68             : 
      69             :         /* First testcase already had SQL opened by read_login_info() */
      70          10 :         strcpy(in_file, INFILE_NAME);
      71             : 
      72             :         /* Execute all testcases (carry on even if one fails) */
      73         190 :         for (n = 1; n <= 100; ++n) {
      74         190 :                 test_file(in_file);
      75         190 :                 sprintf(in_file, "%s_%d", INFILE_NAME, n);
      76         190 :                 if (sql_reopen(in_file) != SUCCEED) {
      77          10 :                         printf("===== End of t0016 subtests =====\n");
      78          10 :                         break;
      79             :                 }
      80             :         }
      81             : 
      82          10 :         dbclose(dbproc);
      83          10 :         dbexit();
      84             : 
      85          10 :         printf("dblib %s on %s\n", (failed ? "failed!" : "okay"), __FILE__);
      86          10 :         return failed ? 1 : 0;
      87             : }
      88             : 
      89             : static bool got_error = false;
      90             : 
      91             : static int
      92          48 : ignore_msg_handler(DBPROCESS * dbproc TDS_UNUSED, DBINT msgno TDS_UNUSED, int state TDS_UNUSED, int severity TDS_UNUSED,
      93             :                    char *text TDS_UNUSED, char *server TDS_UNUSED, char *proc TDS_UNUSED, int line TDS_UNUSED)
      94             : {
      95          48 :         got_error = true;
      96          48 :         return 0;
      97             : }
      98             : 
      99             : static int
     100          48 : ignore_err_handler(DBPROCESS * dbproc TDS_UNUSED, int severity TDS_UNUSED, int dberr TDS_UNUSED,
     101             :                    int oserr TDS_UNUSED, char *dberrstr TDS_UNUSED, char *oserrstr TDS_UNUSED)
     102             : {
     103          48 :         got_error = true;
     104          48 :         return INT_CANCEL;
     105             : }
     106             : 
     107             : static char line1[1024*16];
     108             : static char line2[1024*16];
     109             : 
     110             : static void
     111         190 : test_file(const char *fn)
     112             : {
     113             :         int i;
     114             :         RETCODE ret;
     115         190 :         int num_cols = 0;
     116         190 :         const char *out_file = "t0016.out";
     117         190 :         const char *err_file = "t0016.err";
     118             :         DBINT rows_copied;
     119         190 :         unsigned num_rows = 2;
     120             :         char table_name[64];
     121             :         char hints[64];
     122             : 
     123             :         FILE *input_file;
     124             : 
     125             :         char sql_file[256];
     126             :         char in_file[256];
     127             :         char exp_file[256];
     128             : 
     129         190 :         snprintf(sql_file, sizeof(sql_file), "%s/%s.sql", FREETDS_SRCDIR, fn);
     130         190 :         snprintf(in_file, sizeof(in_file), "%s/%s.in", FREETDS_SRCDIR, fn);
     131         190 :         snprintf(exp_file, sizeof(exp_file), "%s/%s.exp", FREETDS_SRCDIR, fn);
     132             : 
     133         190 :         strlcpy(table_name, TABLE_NAME, sizeof(table_name));
     134         190 :         hints[0] = 0;
     135             : 
     136         190 :         printf("===== %s =====\n", fn);
     137         190 :         input_file = fopen(in_file, "r");
     138         190 :         if (!input_file) {
     139           0 :                 sprintf(in_file, "%s.in", fn);
     140           0 :                 sprintf(exp_file, "%s.exp", fn);
     141           0 :                 input_file = fopen(in_file, "rb");
     142             :         }
     143         190 :         if (!input_file) {
     144           0 :                 fprintf(stderr, "could not open %s\n", in_file);
     145           0 :                 exit(1);
     146             :         }
     147         190 :         num_rows = count_file_rows(input_file);
     148         190 :         fclose(input_file);
     149             : 
     150         190 :         input_file = fopen(exp_file, "r");
     151         190 :         if (!input_file)
     152         170 :                 strcpy(exp_file, in_file);
     153             :         else
     154          20 :                 fclose(input_file);
     155             : 
     156         190 :         input_file = fopen(sql_file, "r");
     157         190 :         assert(input_file);
     158             :         for (;;) {
     159             :                 const char *param;
     160         210 :                 size_t len = fgets_raw(line1, sizeof(line1), input_file);
     161             : 
     162         210 :                 if (len && line1[len - 1] == '\n')
     163         210 :                         line1[len - 1] = '\0';
     164         210 :                 if (len == 0 || strncmp(line1, "-- PARAM:", 9) != 0)
     165             :                         break;
     166          20 :                 param = line1 + 9;
     167          20 :                 if (strncmp(param, "table ", 6) == 0) {
     168          10 :                         param += 6;
     169          10 :                         strlcpy(table_name, param, sizeof(table_name));
     170          10 :                 } else if (strncmp(param, "hints ", 6) == 0) {
     171          10 :                         param += 6;
     172          10 :                         strlcpy(hints, param, sizeof(hints));
     173             :                 } else {
     174           0 :                         fprintf(stderr, "invalid parameter: %s\n", param);
     175           0 :                         exit(1);
     176             :                 }
     177             :         }
     178         190 :         fclose(input_file);
     179             : 
     180         190 :         dberrhandle(ignore_err_handler);
     181         190 :         dbmsghandle(ignore_msg_handler);
     182             : 
     183         190 :         printf("Creating table '%s'\n", table_name);
     184         190 :         got_error = false;
     185         190 :         sql_cmd(dbproc);
     186         190 :         dbsqlexec(dbproc);
     187         598 :         while (dbresults(dbproc) != NO_MORE_RESULTS)
     188         218 :                 continue;
     189             : 
     190         190 :         dberrhandle(syb_err_handler);
     191         190 :         dbmsghandle(syb_msg_handler);
     192             : 
     193         190 :         if (got_error) {
     194          36 :                 printf("Skipping %s due to table creation failure.\n", fn);
     195          36 :                 return;
     196             :         }
     197             : 
     198         154 :         ret = sql_cmd(dbproc);
     199         154 :         printf("return from dbcmd = %d\n", ret);
     200             : 
     201         154 :         ret = dbsqlexec(dbproc);
     202         154 :         printf("return from dbsqlexec = %d\n", ret);
     203             : 
     204         154 :         if (dbresults(dbproc) != FAIL) {
     205         154 :                 num_cols = dbnumcols(dbproc);
     206         154 :                 printf("Number of columns = %d\n", num_cols);
     207             : 
     208         308 :                 while (dbnextrow(dbproc) != NO_MORE_ROWS)
     209           0 :                         continue;
     210             :         }
     211             : 
     212             :         /* BCP in */
     213             : 
     214         154 :         printf("bcp_init with in_file as '%s'\n", in_file);
     215         154 :         ret = bcp_init(dbproc, table_name, in_file, (char*) err_file, DB_IN);
     216         154 :         if (ret != SUCCEED)
     217           0 :                 failure("bcp_init failed\n");
     218             : 
     219         154 :         if (hints[0])
     220           2 :                 bcp_options(dbproc, BCPHINTS, (BYTE *) hints, strlen(hints));
     221             : 
     222         154 :         printf("return from bcp_init = %d\n", ret);
     223             : 
     224         154 :         ret = bcp_columns(dbproc, num_cols);
     225         154 :         if (ret != SUCCEED)
     226           0 :                 failure("bcp_columns failed\n");
     227         154 :         printf("return from bcp_columns = %d\n", ret);
     228             : 
     229         824 :         for (i = 1; i < num_cols; i++) {
     230         670 :                 if ((ret = bcp_colfmt(dbproc, i, SYBCHAR, 0, -1, (BYTE *) "\t", sizeof(char), i)) == FAIL)
     231           0 :                         failure("return from bcp_colfmt = %d\n", ret);
     232             :         }
     233             : 
     234         154 :         if ((ret = bcp_colfmt(dbproc, num_cols, SYBCHAR, 0, -1, (BYTE *) "\n", sizeof(char), num_cols)) == FAIL)
     235           0 :                 failure("return from bcp_colfmt = %d\n", ret);
     236             : 
     237             : 
     238         154 :         ret = bcp_exec(dbproc, &rows_copied);
     239         154 :         if (ret != SUCCEED || rows_copied != num_rows)
     240           0 :                 failure("bcp_exec failed\n");
     241             : 
     242         154 :         printf("%d rows copied in\n", rows_copied);
     243             : 
     244             :         /* BCP out */
     245             : 
     246         154 :         rows_copied = 0;
     247         154 :         ret = bcp_init(dbproc, table_name, (char *) out_file, (char *) err_file, DB_OUT);
     248         154 :         if (ret != SUCCEED)
     249           0 :                 failure("bcp_int failed\n");
     250             : 
     251         154 :         printf("select\n");
     252         154 :         sql_cmd(dbproc);
     253         154 :         dbsqlexec(dbproc);
     254             : 
     255         154 :         if (dbresults(dbproc) != FAIL) {
     256         154 :                 num_cols = dbnumcols(dbproc);
     257         308 :                 while (dbnextrow(dbproc) != NO_MORE_ROWS)
     258           0 :                         continue;
     259             :         }
     260             : 
     261         154 :         ret = bcp_columns(dbproc, num_cols);
     262             : 
     263         824 :         for (i = 1; i < num_cols; i++) {
     264         670 :                 if ((ret = bcp_colfmt(dbproc, i, SYBCHAR, 0, -1, (BYTE *) "\t", sizeof(char), i)) == FAIL)
     265           0 :                         failure("return from bcp_colfmt = %d\n", ret);
     266             :         }
     267             : 
     268         154 :         if ((ret = bcp_colfmt(dbproc, num_cols, SYBCHAR, 0, -1, (BYTE *) "\n", sizeof(char), num_cols)) == FAIL)
     269           0 :                 failure("return from bcp_colfmt = %d\n", ret);
     270             : 
     271         154 :         ret = bcp_exec(dbproc, &rows_copied);
     272         154 :         if (ret != SUCCEED || rows_copied != num_rows)
     273           0 :                 failure("bcp_exec failed\n");
     274             : 
     275         154 :         printf("%d rows copied out\n", rows_copied);
     276             : 
     277         154 :         printf("Dropping table '%s'\n", table_name);
     278         154 :         sql_cmd(dbproc);
     279         154 :         dbsqlexec(dbproc);
     280         466 :         while (dbresults(dbproc) != NO_MORE_RESULTS)
     281         158 :                 continue;
     282             : 
     283         154 :         if (failed)
     284             :                 return;
     285             : 
     286         154 :         if (compare_files(exp_file, out_file))
     287         154 :                 printf("Input and output files are equal\n");
     288             :         else
     289           0 :                 failed = true;
     290             : }
     291             : 
     292             : static size_t
     293        1910 : fgets_raw(char *s, int len, FILE *f)
     294             : {
     295        1910 :         char *p = s;
     296             : 
     297      767832 :         while (len > 1) {
     298      765922 :                 int c = getc(f);
     299      765922 :                 if (c == EOF) {
     300         498 :                         if (ferror(f))
     301             :                                 return 0;
     302             :                         break;
     303             :                 }
     304      765424 :                 *p++ = c;
     305      765424 :                 --len;
     306      765424 :                 if (c == '\n')
     307             :                         break;
     308             :         }
     309        1910 :         if (len > 0)
     310        1910 :                 *p = 0;
     311        1910 :         return p - s;
     312             : }
     313             : 
     314             : static bool
     315         154 : compare_files(const char *fn1, const char *fn2)
     316             : {
     317         154 :         bool equal = true;
     318             :         FILE *f1, *f2;
     319             :         size_t s1, s2;
     320             : 
     321             :         /* check input and output should be the same */
     322         154 :         f1 = fopen(fn1, "r");
     323         154 :         f2 = fopen(fn2, "r");
     324         154 :         if (f1 != NULL && f2 != NULL) {
     325             :                 int line = 1;
     326             : 
     327         366 :                 for (;; ++line) {
     328         886 :                         s1 = fgets_raw(line1, sizeof(line1), f1);
     329         520 :                         s2 = fgets_raw(line2, sizeof(line2), f2);
     330             : 
     331             :                         /* EOF or error of one */
     332         520 :                         if (!!s1 != !!s2) {
     333           0 :                                 equal = false;
     334           0 :                                 failure("error reading a file or EOF of a file\n");
     335           0 :                                 break;
     336             :                         }
     337             : 
     338             :                         /* EOF or error of both */
     339         520 :                         if (!s1) {
     340         154 :                                 if (feof(f1) && feof(f2))
     341             :                                         break;
     342           0 :                                 equal = false;
     343           0 :                                 failure("error reading a file\n");
     344           0 :                                 break;
     345             :                         }
     346             : 
     347         366 :                         if (s1 != s2 || memcmp(line1, line2, s1) != 0) {
     348           0 :                                 equal = false;
     349           0 :                                 failure("File different at line %d\n"
     350             :                                         "  input: %s"
     351             :                                         " output: %s",
     352             :                                         line, line1, line2);
     353             :                         }
     354             :                 }
     355             :         } else {
     356           0 :                 equal = false;
     357           0 :                 failure("error opening files\n");
     358             :         }
     359         154 :         if (f1)
     360         154 :                 fclose(f1);
     361         154 :         if (f2)
     362         154 :                 fclose(f2);
     363             : 
     364         154 :         return equal;
     365             : }
     366             : 
     367             : static unsigned
     368         190 : count_file_rows(FILE *f)
     369             : {
     370             :         size_t s;
     371         190 :         unsigned rows = 1;
     372         190 :         char last = '\n';
     373             : 
     374         190 :         assert(f);
     375             : 
     376         660 :         while ((s = fgets_raw(line1, sizeof(line1), f)) != 0) {
     377         470 :                 last = line1[s-1];
     378         470 :                 if (last == '\n')
     379         470 :                         ++rows;
     380             :         }
     381         190 :         if (last == '\n')
     382         190 :                 --rows;
     383         190 :         assert(!ferror(f));
     384         190 :         return rows;
     385             : }

Generated by: LCOV version 1.13