LCOV - code coverage report
Current view: top level - src/ctlib/unittests - common.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 127 209 60.8 %
Date: 2025-12-03 08:48:55 Functions: 15 15 100.0 %

          Line data    Source code
       1             : #include "common.h"
       2             : 
       3             : #if HAVE_UNISTD_H
       4             : #include <unistd.h>
       5             : #endif
       6             : 
       7             : #include <freetds/replacements.h>
       8             : #include <freetds/macros.h>
       9             : 
      10             : static const char *BASENAME = NULL;
      11             : 
      12             : static const char *PWD = DEFAULT_PWD_PATH;
      13             : 
      14             : int cslibmsg_cb_invoked = 0;
      15             : int clientmsg_cb_invoked = 0;
      16             : int servermsg_cb_invoked = 0;
      17             : bool error_to_stdout = false;
      18             : 
      19             : ct_message ct_last_message;
      20             : 
      21             : static CS_RETCODE continue_logging_in(CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose);
      22             : 
      23             : CS_RETCODE
      24          10 : read_login_info(void)
      25             : {
      26        1340 :         const char *s = read_login_info_base(&common_pwd, DEFAULT_PWD_PATH);
      27             : 
      28        1310 :         return s ? CS_SUCCEED : CS_FAIL;
      29             : }
      30             : 
      31             : static CS_RETCODE
      32          30 : establish_login(int argc, char **argv)
      33             : {
      34             :         extern char *optarg;
      35             :         extern int optind;
      36             :         int ch;
      37             : 
      38          30 :         BASENAME = basename((char *)argv[0]);
      39             : 
      40             :         /* process command line options (handy for manual testing) */
      41          60 :         while ((ch = getopt(argc, argv, "U:P:S:D:f:m:v")) != -1) {
      42           0 :                 switch (ch) {
      43           0 :                 case 'U':
      44           0 :                         strlcpy(common_pwd.user, optarg, sizeof(common_pwd.user));
      45           0 :                         break;
      46           0 :                 case 'P':
      47           0 :                         strlcpy(common_pwd.password, optarg, sizeof(common_pwd.password));
      48           0 :                         break;
      49           0 :                 case 'S':
      50           0 :                         strlcpy(common_pwd.server, optarg, sizeof(common_pwd.server));
      51           0 :                         break;
      52           0 :                 case 'D':
      53           0 :                         strlcpy(common_pwd.database, optarg, sizeof(common_pwd.database));
      54           0 :                         break;
      55           0 :                 case 'f': /* override default PWD file */
      56           0 :                         PWD = strdup(optarg);
      57           0 :                         break;
      58           0 :                 case 'm':
      59           0 :                         common_pwd.maxlength = (CS_INT) strtol(optarg, NULL, 10);
      60           0 :                 case 'v':
      61           0 :                         common_pwd.fverbose = 1;
      62           0 :                         break;
      63           0 :                 case '?':
      64             :                 default:
      65           0 :                         fprintf(stderr, "usage:  %s [-v] [-f PWD]\n"
      66             :                                         "        [-U username] [-P password]\n"
      67             :                                         "        [-S servername] [-D database]\n"
      68             :                                         , BASENAME);
      69           0 :                         exit(1);
      70             :                 }
      71             :         }
      72          30 :         read_login_info();
      73             : 
      74             :         /* user is not necessary for MSSQL trusted logins */
      75          30 :         return (*common_pwd.server && *common_pwd.database) ? CS_SUCCEED : CS_FAIL;
      76             : }
      77             : 
      78             : CS_RETCODE
      79          30 : try_ctlogin_with_options(int argc, char **argv, CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose)
      80             : {
      81             :         CS_RETCODE ret;
      82             : 
      83          30 :         if ((ret = establish_login(argc, argv)) != CS_SUCCEED) {
      84           0 :                 if (verbose) {
      85           0 :                         fprintf(stderr, "read_login_info() failed!\n");
      86             :                 }
      87             :                 return ret;
      88             :         }
      89          30 :         return continue_logging_in(ctx, conn, cmd, verbose);
      90             : }
      91             : 
      92             : /* old way: because I'm too lazy to change every unit test */
      93             : CS_RETCODE
      94        1300 : try_ctlogin(CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose)
      95             : {
      96             :         CS_RETCODE ret;
      97             : 
      98        1300 :         if ((ret = read_login_info()) != CS_SUCCEED) {
      99           0 :                 if (verbose) {
     100           0 :                         fprintf(stderr, "read_login_info() failed!\n");
     101             :                 }
     102             :                 return ret;
     103             :         }
     104        1300 :         return continue_logging_in(ctx, conn, cmd, verbose);
     105             : }
     106             : 
     107             : CS_RETCODE
     108        1330 : continue_logging_in(CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose)
     109             : {
     110             :         CS_RETCODE ret;
     111             :         char query[512+10];
     112        1330 :         CS_INT bulk_enabled = CS_TRUE;
     113        1330 :         CS_INT convfmt = CS_DATES_SHORT;
     114             : 
     115        1330 :         ret = cs_ctx_alloc(CS_VERSION_100, ctx);
     116        1330 :         if (ret != CS_SUCCEED) {
     117           0 :                 if (verbose) {
     118           0 :                         fprintf(stderr, "Context Alloc failed!\n");
     119             :                 }
     120             :                 return ret;
     121             :         }
     122             : 
     123        1330 :         ret = cs_dt_info(*ctx, CS_SET, NULL, CS_DT_CONVFMT, CS_UNUSED, &convfmt, sizeof(convfmt), NULL);
     124        1330 :         if (ret != CS_SUCCEED) {
     125           0 :                 if (verbose) {
     126           0 :                         fprintf(stderr, "Date format initialization failed\n");
     127             :                 }
     128             :                 return ret;
     129             :         }
     130             : 
     131        1330 :         ret = ct_init(*ctx, CS_VERSION_100);
     132        1330 :         if (ret != CS_SUCCEED) {
     133           0 :                 if (verbose) {
     134           0 :                         fprintf(stderr, "Library Init failed!\n");
     135             :                 }
     136             :                 return ret;
     137             :         }
     138        1330 :         if ((ret = ct_callback(*ctx, NULL, CS_SET, CS_CLIENTMSG_CB,
     139             :                                (CS_VOID*) clientmsg_cb)) != CS_SUCCEED) {
     140           0 :                 fprintf(stderr, "ct_callback() failed\n");
     141           0 :                 return ret;
     142             :         }
     143        1330 :         if ((ret = ct_callback(*ctx, NULL, CS_SET, CS_SERVERMSG_CB, servermsg_cb)) != CS_SUCCEED) {
     144           0 :                 fprintf(stderr, "ct_callback() failed\n");
     145           0 :                 return ret;
     146             :         }
     147        1330 :         ret = ct_con_alloc(*ctx, conn);
     148        1330 :         if (ret != CS_SUCCEED) {
     149           0 :                 if (verbose) {
     150           0 :                         fprintf(stderr, "Connect Alloc failed!\n");
     151             :                 }
     152             :                 return ret;
     153             :         }
     154        1330 :         ret = ct_con_props(*conn, CS_SET, CS_USERNAME, common_pwd.user, CS_NULLTERM, NULL);
     155        1330 :         if (ret != CS_SUCCEED) {
     156           0 :                 if (verbose) {
     157           0 :                         fprintf(stderr, "ct_con_props() SET USERNAME failed!\n");
     158             :                 }
     159             :                 return ret;
     160             :         }
     161        1330 :         ret = ct_con_props(*conn, CS_SET, CS_PASSWORD, common_pwd.password, CS_NULLTERM, NULL);
     162        1330 :         if (ret != CS_SUCCEED) {
     163           0 :                 if (verbose) {
     164           0 :                         fprintf(stderr, "ct_con_props() SET PASSWORD failed!\n");
     165             :                 }
     166             :                 return ret;
     167             :         }
     168        1330 :         ret = ct_con_props(*conn, CS_SET, CS_BULK_LOGIN, &bulk_enabled, CS_UNUSED, NULL);
     169        1330 :         if (ret != CS_SUCCEED) {
     170           0 :                 if (verbose) {
     171           0 :                         fprintf(stderr, "ct_con_props() SET BULK failed!\n");
     172             :                 }
     173             :                 return ret;
     174             :         }
     175             : 
     176        1330 :         printf("connecting as %s to %s.%s\n", common_pwd.user, common_pwd.server, common_pwd.database);
     177             : 
     178        1330 :         ret = ct_connect(*conn, common_pwd.server, CS_NULLTERM);
     179        1330 :         if (ret != CS_SUCCEED) {
     180           0 :                 if (verbose) {
     181           0 :                         fprintf(stderr, "Connection failed!\n");
     182             :                 }
     183           0 :                 ct_con_drop(*conn);
     184           0 :                 *conn = NULL;
     185           0 :                 ct_exit(*ctx, CS_UNUSED);
     186           0 :                 cs_ctx_drop(*ctx);
     187           0 :                 *ctx = NULL;
     188           0 :                 return ret;
     189             :         }
     190        1330 :         ret = ct_cmd_alloc(*conn, cmd);
     191        1330 :         if (ret != CS_SUCCEED) {
     192           0 :                 if (verbose) {
     193           0 :                         fprintf(stderr, "Command Alloc failed!\n");
     194             :                 }
     195           0 :                 ct_con_drop(*conn);
     196           0 :                 *conn = NULL;
     197           0 :                 ct_exit(*ctx, CS_UNUSED);
     198           0 :                 cs_ctx_drop(*ctx);
     199           0 :                 *ctx = NULL;
     200           0 :                 return ret;
     201             :         }
     202             : 
     203        1330 :         sprintf(query, "use %s", common_pwd.database);
     204             : 
     205        1330 :         ret = run_command(*cmd, query);
     206        1330 :         if (ret != CS_SUCCEED)
     207             :                 return ret;
     208             : 
     209        1330 :         return CS_SUCCEED;
     210             : }
     211             : 
     212             : 
     213             : CS_RETCODE
     214        1330 : try_ctlogout(CS_CONTEXT * ctx, CS_CONNECTION * conn, CS_COMMAND * cmd, int verbose)
     215             : {
     216             :         CS_RETCODE ret;
     217             : 
     218        1330 :         ret = ct_cancel(conn, NULL, CS_CANCEL_ALL);
     219        1330 :         if (ret != CS_SUCCEED) {
     220           0 :                 if (verbose) {
     221           0 :                         fprintf(stderr, "ct_cancel() failed!\n");
     222             :                 }
     223             :                 return ret;
     224             :         }
     225        1330 :         ct_cmd_drop(cmd);
     226        1330 :         ct_close(conn, CS_UNUSED);
     227        1330 :         ct_con_drop(conn);
     228        1330 :         ct_exit(ctx, CS_UNUSED);
     229        1330 :         cs_ctx_drop(ctx);
     230             : 
     231        1330 :         return CS_SUCCEED;
     232             : }
     233             : 
     234             : /* Run commands from which we expect no results returned */
     235             : CS_RETCODE
     236        2456 : run_command(CS_COMMAND * cmd, const char *sql)
     237             : {
     238             :         CS_RETCODE ret, results_ret;
     239             :         CS_INT result_type;
     240             : 
     241        2456 :         if (cmd == NULL) {
     242             :                 return CS_FAIL;
     243             :         }
     244             : 
     245        2456 :         ret = ct_command(cmd, CS_LANG_CMD, (void *) sql, CS_NULLTERM, CS_UNUSED);
     246        2456 :         if (ret != CS_SUCCEED) {
     247           0 :                 fprintf(stderr, "ct_command() failed\n");
     248           0 :                 return ret;
     249             :         }
     250        2456 :         ret = ct_send(cmd);
     251        2456 :         if (ret != CS_SUCCEED) {
     252           2 :                 fprintf(stderr, "ct_send() failed\n");
     253           2 :                 return ret;
     254             :         }
     255             :         ret = CS_SUCCEED;
     256        7558 :         while ((results_ret = ct_results(cmd, &result_type)) == CS_SUCCEED) {
     257        5104 :                 switch (result_type) {
     258             :                 case CS_CMD_SUCCEED:
     259             :                         break;
     260             :                 case CS_CMD_DONE:
     261             :                         break;
     262          68 :                 case CS_CMD_FAIL:
     263          68 :                         fprintf(stderr, "ct_results() result_type CS_CMD_FAIL.\n");
     264          68 :                         ret = CS_FAIL;
     265          68 :                         break;
     266           0 :                 default:
     267           0 :                         fprintf(stderr, "ct_results() unexpected result_type.\n");
     268           0 :                         return CS_FAIL;
     269             :                 }
     270             :         }
     271        2454 :         switch (results_ret) {
     272             :         case CS_END_RESULTS:
     273             :                 break;
     274           0 :         case CS_FAIL:
     275           0 :                 fprintf(stderr, "ct_results() failed.\n");
     276           0 :                 return CS_FAIL;
     277             :                 break;
     278           0 :         default:
     279           0 :                 fprintf(stderr, "ct_results() unexpected return.\n");
     280           0 :                 return CS_FAIL;
     281             :         }
     282             : 
     283             :         return ret;
     284             : }
     285             : 
     286             : CS_INT
     287         300 : cslibmsg_cb(CS_CONTEXT * connection TDS_UNUSED, CS_CLIENTMSG * errmsg)
     288             : {
     289         300 :         cslibmsg_cb_invoked++;
     290             : 
     291             :         ct_reset_last_message();
     292         300 :         ct_last_message.type = CTMSG_CSLIB;
     293         300 :         ct_last_message.number = errmsg->msgnumber;
     294         300 :         strlcpy(ct_last_message.text, errmsg->msgstring, sizeof(ct_last_message.text));
     295             : 
     296         300 :         fprintf(stderr, "\nCS-Library Message:\n");
     297        1200 :         fprintf(stderr, "number %#x layer %d origin %d severity %d number %d\n",
     298             :                 errmsg->msgnumber,
     299         600 :                 (int) CS_LAYER(errmsg->msgnumber), (int) CS_ORIGIN(errmsg->msgnumber),
     300         600 :                 (int) CS_SEVERITY(errmsg->msgnumber), (int) CS_NUMBER(errmsg->msgnumber));
     301         300 :         fprintf(stderr, "msgstring: %s\n", errmsg->msgstring);
     302         300 :         fprintf(stderr, "osstring: %s\n", (errmsg->osstringlen > 0)
     303             :                 ? errmsg->osstring : "(null)");
     304         300 :         return CS_SUCCEED;
     305             : }
     306             : 
     307             : 
     308             : 
     309             : static CS_RETCODE
     310         539 : clientmsg_gen_cb(CS_CONTEXT * context, CS_CONNECTION * connection, CS_CLIENTMSG * errmsg,
     311             :                  ct_message_type msg_type)
     312             : {
     313         539 :         FILE *out = error_to_stdout ? stdout: stderr;
     314             : 
     315         539 :         clientmsg_cb_invoked++;
     316             : 
     317             :         ct_reset_last_message();
     318         539 :         ct_last_message.type = msg_type;
     319         539 :         ct_last_message.number = errmsg->msgnumber;
     320         539 :         strlcpy(ct_last_message.text, errmsg->msgstring, sizeof(ct_last_message.text));
     321             : 
     322         539 :         fprintf(out, "\nOpen Client Message%s: %p %p\n",
     323             :                 msg_type == CTMSG_CLIENT ? "" : " #2", context, connection);
     324        2156 :         fprintf(out, "number %#x layer %d origin %d severity %d number %d\n",
     325             :                 errmsg->msgnumber,
     326        1078 :                 (int) CS_LAYER(errmsg->msgnumber), (int) CS_ORIGIN(errmsg->msgnumber),
     327        1078 :                 (int) CS_SEVERITY(errmsg->msgnumber), (int) CS_NUMBER(errmsg->msgnumber));
     328         539 :         fprintf(out, "msgstring: %s\n", errmsg->msgstring);
     329         539 :         fprintf(out, "osstring: %s\n", (errmsg->osstringlen > 0)
     330             :                 ? errmsg->osstring : "(null)");
     331         539 :         fflush(out);
     332         539 :         return CS_SUCCEED;
     333             : }
     334             : 
     335             : CS_RETCODE
     336          89 : clientmsg_cb(CS_CONTEXT * context, CS_CONNECTION * connection, CS_CLIENTMSG * errmsg)
     337             : {
     338          89 :         return clientmsg_gen_cb(context, connection, errmsg, CTMSG_CLIENT);
     339             : }
     340             : 
     341             : CS_RETCODE
     342         450 : clientmsg_cb2(CS_CONTEXT * context, CS_CONNECTION * connection, CS_CLIENTMSG * errmsg)
     343             : {
     344         450 :         return clientmsg_gen_cb(context, connection, errmsg, CTMSG_CLIENT2);
     345             : }
     346             : 
     347             : CS_RETCODE
     348        4116 : servermsg_cb(CS_CONTEXT * context TDS_UNUSED, CS_CONNECTION * connection TDS_UNUSED, CS_SERVERMSG * srvmsg)
     349             : {
     350        4116 :         FILE *out = error_to_stdout ? stdout: stderr;
     351             : 
     352        4116 :         servermsg_cb_invoked++;
     353             : 
     354             :         ct_reset_last_message();
     355        4116 :         ct_last_message.type = CTMSG_SERVER;
     356        4116 :         ct_last_message.number = srvmsg->msgnumber;
     357        4116 :         strlcpy(ct_last_message.text, srvmsg->text, sizeof(ct_last_message.text));
     358             : 
     359        4116 :         if (srvmsg->msgnumber == 5701 || srvmsg->msgnumber == 5703) {
     360        3724 :                 fprintf(out, "%s\n", srvmsg->text);
     361        3724 :                 fflush(out);
     362        3724 :                 return CS_SUCCEED;
     363             :         }
     364             : 
     365         392 :         fprintf(out, "\nServer message:\n");
     366         784 :         fprintf(out, "%s Message %d severity %d state %d line %d:\n",
     367         392 :                 srvmsg->svrnlen > 0? srvmsg->svrname : "Server",
     368             :                 srvmsg->msgnumber, srvmsg->severity, srvmsg->state, srvmsg->line);
     369         392 :         if (srvmsg->proclen > 0)
     370          24 :                 fprintf(out, "proc %s: ", srvmsg->proc);
     371         392 :         fprintf(out, "\t\"%s\"\n", srvmsg->text);
     372             : 
     373         392 :         fflush(out);
     374         392 :         return CS_SUCCEED;
     375             : }
     376             : 
     377             : const char *
     378         488 : res_type_str(CS_RETCODE ret)
     379             : {
     380             :         static char str[4][32];
     381             :         static uint8_t last_used;
     382             :         uint8_t n;
     383             : 
     384             : #define S(s) case s: return #s;
     385         488 :         switch ((int) ret) {
     386             :         S(CS_ROW_RESULT)
     387           0 :         S(CS_PARAM_RESULT)
     388          82 :         S(CS_STATUS_RESULT)
     389           0 :         S(CS_MSG_RESULT)
     390          80 :         S(CS_CMD_SUCCEED)
     391         186 :         S(CS_CMD_DONE)
     392          12 :         S(CS_CMD_FAIL)
     393          24 :         S(CS_COMPUTE_RESULT)
     394             : #undef S
     395             :         }
     396             : 
     397           0 :         n = (last_used++) & 3;
     398           0 :         snprintf(str[n], sizeof(str[0]), "?? (%d)", (int) ret);
     399           0 :         return str[n];
     400             : }
     401             : 
     402             : void
     403       12286 : _check_ret(const char *name, CS_RETCODE ret, int line)
     404             : {
     405       12286 :         if (ret != CS_SUCCEED) {
     406           0 :                 fprintf(stderr, "%s():%d: failed\n", name, line);
     407           0 :                 exit(1);
     408             :         }
     409       12286 : }
     410             : 
     411             : void
     412         830 : ct_reset_last_message(void)
     413             : {
     414        5785 :         memset(&ct_last_message, 0, sizeof(ct_last_message));
     415         830 : }

Generated by: LCOV version 1.13