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

Generated by: LCOV version 1.13