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

Generated by: LCOV version 1.13