LCOV - code coverage report
Current view: top level - src/apps - tsql.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 211 455 46.4 %
Date: 2024-03-23 08:24:27 Functions: 7 11 63.6 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns
       3             :  * Copyright (C) 2006-2015  Frediano Ziglio
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or
       6             :  * modify it under the terms of the GNU Library General Public
       7             :  * License as published by the Free Software Foundation; either
       8             :  * version 2 of the License, or (at your option) any later version.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * Library General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU Library General Public
      16             :  * License along with this library; if not, write to the
      17             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      18             :  * Boston, MA 02111-1307, USA.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : 
      23             : #include <freetds/time.h>
      24             : 
      25             : #include <stdio.h>
      26             : #include <assert.h>
      27             : #include <ctype.h>
      28             : #if HAVE_FORK
      29             : #include <sys/wait.h>
      30             : #endif
      31             : #include <signal.h>
      32             : 
      33             : #ifdef HAVE_READLINE
      34             : #include <readline/readline.h>
      35             : #include <readline/history.h>
      36             : #endif /* HAVE_READLINE */
      37             : 
      38             : #if HAVE_ERRNO_H
      39             : #include <errno.h>
      40             : #endif /* HAVE_ERRNO_H */
      41             : 
      42             : #if HAVE_STDLIB_H
      43             : #include <stdlib.h>
      44             : #endif /* HAVE_STDLIB_H */
      45             : 
      46             : #if HAVE_STRING_H
      47             : #include <string.h>
      48             : #endif /* HAVE_STRING_H */
      49             : 
      50             : #if HAVE_UNISTD_H
      51             : # include <unistd.h>
      52             : #elif defined(_WIN32)
      53             : # include <io.h>
      54             : # undef isatty
      55             : # define isatty(fd) _isatty(fd)
      56             : #endif /* HAVE_UNISTD_H */
      57             : 
      58             : /* HP-UX require some constants defined by limits.h */
      59             : #ifdef HAVE_LIMITS_H
      60             : #include <limits.h>
      61             : #endif /* HAVE_LIMITS_H */
      62             : 
      63             : #if defined(__hpux__) && !defined(_POSIX_PATH_MAX)
      64             : #define _POSIX_PATH_MAX 255
      65             : #endif
      66             : 
      67             : #ifdef HAVE_LOCALE_H
      68             : #include <locale.h>
      69             : #endif /* HAVE_LOCALE_H */
      70             : 
      71             : #ifdef HAVE_LANGINFO_H
      72             : #include <langinfo.h>
      73             : #endif /* HAVE_LANGINFO_H */
      74             : 
      75             : #ifdef HAVE_LOCALCHARSET_H
      76             : #include <localcharset.h>
      77             : #endif /* HAVE_LOCALCHARSET_H */
      78             : 
      79             : #include <freetds/tds.h>
      80             : #include <freetds/iconv.h>
      81             : #include <freetds/utils/string.h>
      82             : #include <freetds/convert.h>
      83             : #include <freetds/data.h>
      84             : #include <freetds/utils.h>
      85             : #include <freetds/replacements.h>
      86             : 
      87             : #define TDS_ISSPACE(c) isspace((unsigned char) (c))
      88             : 
      89             : enum
      90             : {
      91             :         OPT_VERSION =  0x01,
      92             :         OPT_TIMER =    0x02,
      93             :         OPT_NOFOOTER = 0x04,
      94             :         OPT_NOHEADER = 0x08,
      95             :         OPT_QUIET =    0x10,
      96             :         OPT_VERBOSE =  0x20,
      97             :         OPT_INSTANCES= 0x40
      98             : };
      99             : 
     100             : static int istty = 0;
     101             : static int global_opt_flags = 0;
     102             : 
     103             : #define QUIET (global_opt_flags & OPT_QUIET)
     104             : #define VERBOSE (global_opt_flags & OPT_VERBOSE)
     105             : 
     106             : static const char *opt_col_term = "\t";
     107             : static const char *opt_row_term = "\n";
     108             : static const char *opt_default_db = NULL;
     109             : 
     110             : static int tsql_handle_message(const TDSCONTEXT * context, TDSSOCKET * tds, TDSMESSAGE * msg);
     111             : 
     112             : static char *
     113          30 : tsql_readline(char *prompt)
     114             : {
     115             :         size_t sz, pos;
     116             :         char *line, *p;
     117             : 
     118             : #ifdef HAVE_READLINE
     119          30 :         if (istty)
     120           0 :                 return readline(prompt);
     121             : #endif
     122             : 
     123          30 :         sz = 1024;
     124          30 :         pos = 0;
     125          30 :         line = tds_new(char, sz);
     126          30 :         if (!line)
     127             :                 return NULL;
     128             : 
     129          30 :         if (prompt && prompt[0])
     130          30 :                 printf("%s", prompt);
     131             :         for (;;) {
     132             :                 /* read a piece */
     133          30 :                 if (fgets(line + pos, (int)(sz - pos), stdin) == NULL) {
     134           0 :                         if (pos)
     135           0 :                                 return line;
     136             :                         break;
     137             :                 }
     138             : 
     139             :                 /* got end-of-line ? */
     140          30 :                 p = strchr(line + pos, '\n');
     141          30 :                 if (p) {
     142          30 :                         *p = 0;
     143          30 :                         return line;
     144             :                 }
     145             : 
     146             :                 /* allocate space if needed */
     147           0 :                 pos += strlen(line + pos);
     148           0 :                 if (pos + 1024 >= sz) {
     149           0 :                         sz += 1024;
     150           0 :                         if (!TDS_RESIZE(line, sz))
     151             :                                 break;
     152             :                 }
     153             :         }
     154           0 :         free(line);
     155           0 :         return NULL;
     156             : }
     157             : 
     158             : static void
     159             : tsql_add_history(const char *s TDS_UNUSED)
     160             : {
     161             : #ifdef HAVE_READLINE
     162          10 :         if (istty)
     163           0 :                 add_history(s);
     164             : #endif
     165             : }
     166             : 
     167             : /**
     168             :  * Returns the version of the TDS protocol in effect for the link
     169             :  * as a decimal integer.  
     170             :  *      Typical returned values are 42, 50, 70, 80.
     171             :  * Also fills pversion_string unless it is null.
     172             :  *      Typical pversion_string values are "4.2" and "7.0".
     173             :  */
     174             : static int
     175             : tds_version(TDSCONNECTION * conn, char *pversion_string)
     176             : {
     177           0 :         int iversion = 0;
     178             : 
     179           0 :         iversion = 10 * TDS_MAJOR(conn) + TDS_MINOR(conn);
     180             : 
     181           0 :         sprintf(pversion_string, "%d.%d", TDS_MAJOR(conn), TDS_MINOR(conn));
     182             : 
     183             :         return iversion;
     184             : }
     185             : 
     186             : static int
     187          10 : do_query(TDSSOCKET * tds, char *buf, int opt_flags)
     188             : {
     189          10 :         int rows = 0;
     190             :         TDSRET rc;
     191             :         int i;
     192             :         TDSCOLUMN *col;
     193             :         int ctype;
     194             :         CONV_RESULT dres;
     195             :         unsigned char *src;
     196             :         TDS_INT srclen;
     197             :         TDS_INT resulttype;
     198             :         struct timeval start, stop;
     199          10 :         int print_rows = 1;
     200             :         char message[128];
     201             : 
     202          10 :         rc = tds_submit_query(tds, buf);
     203          10 :         if (TDS_FAILED(rc)) {
     204           0 :                 fprintf(stderr, "tds_submit_query() failed\n");
     205           0 :                 return 1;
     206             :         }
     207             : 
     208          30 :         while ((rc = tds_process_tokens(tds, &resulttype, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
     209          20 :                 const int stop_mask = TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE;
     210          20 :                 if (opt_flags & OPT_TIMER) {
     211           0 :                         gettimeofday(&start, NULL);
     212           0 :                         print_rows = 0;
     213             :                 }
     214          20 :                 switch (resulttype) {
     215          10 :                 case TDS_ROWFMT_RESULT:
     216          10 :                         if ((!(opt_flags & OPT_NOHEADER)) && tds->current_results) {
     217          10 :                                 for (i = 0; i < tds->current_results->num_cols; i++) {
     218          10 :                                         if (i) fputs(opt_col_term, stdout);
     219          20 :                                         fputs(tds_dstr_cstr(&tds->current_results->columns[i]->column_name), stdout);
     220             :                                 }
     221          10 :                                 fputs(opt_row_term, stdout);
     222             :                         }
     223             :                         break;
     224             :                 case TDS_COMPUTE_RESULT:
     225             :                 case TDS_ROW_RESULT:
     226             :                         rows = 0;
     227          20 :                         while ((rc = tds_process_tokens(tds, &resulttype, NULL, stop_mask)) == TDS_SUCCESS) {
     228          20 :                                 if (resulttype != TDS_ROW_RESULT && resulttype != TDS_COMPUTE_RESULT)
     229             :                                         break;
     230             : 
     231          10 :                                 rows++;
     232             : 
     233          10 :                                 if (!tds->current_results)
     234           0 :                                         continue;
     235             : 
     236          10 :                                 for (i = 0; i < tds->current_results->num_cols; i++) {
     237          10 :                                         col = tds->current_results->columns[i];
     238          10 :                                         if (col->column_cur_size < 0) {
     239           0 :                                                 if (print_rows)  {
     240           0 :                                                         if (i) fputs(opt_col_term, stdout);
     241           0 :                                                         fputs("NULL", stdout);
     242             :                                                 }
     243           0 :                                                 continue;
     244             :                                         }
     245          10 :                                         ctype = tds_get_conversion_type(col->column_type, col->column_size);
     246             : 
     247          10 :                                         src = col->column_data;
     248          10 :                                         if (is_blob_col(col) && col->column_type != SYBVARIANT)
     249           0 :                                                 src = (unsigned char *) ((TDSBLOB *) src)->textvalue;
     250          10 :                                         srclen = col->column_cur_size;
     251             : 
     252             : 
     253          10 :                                         if (tds_convert(tds_get_ctx(tds), ctype, src, srclen, SYBVARCHAR, &dres) < 0)
     254           0 :                                                 continue;
     255          10 :                                         if (print_rows)  {
     256          10 :                                                 if (i) fputs(opt_col_term, stdout);
     257          10 :                                                 fputs(dres.c, stdout);
     258             :                                         }
     259          10 :                                         free(dres.c);
     260             :                                 }
     261          10 :                                 if (print_rows)
     262          10 :                                         fputs(opt_row_term, stdout);
     263             : 
     264             :                         }
     265          10 :                         if (!QUIET) printf("(%d row%s affected)\n", rows, rows == 1 ? "" : "s");
     266             :                         break;
     267           0 :                 case TDS_STATUS_RESULT:
     268           0 :                         if (!QUIET)
     269           0 :                                 printf("(return status = %d)\n", tds->ret_status);
     270             :                         break;
     271             :                 default:
     272             :                         break;
     273             :                 }
     274             : 
     275          20 :                 if (opt_flags & OPT_VERSION) {
     276             :                         char version[64];
     277           0 :                         int line = 0;
     278             : 
     279           0 :                         line = tds_version(tds->conn, version);
     280           0 :                         if (line) {
     281             :                                 TDSMESSAGE msg;
     282           0 :                                 memset(&msg, 0, sizeof(TDSMESSAGE));
     283           0 :                                 msg.server = "tsql";
     284           0 :                                 sprintf(message, "using TDS version %s", version);
     285           0 :                                 msg.message = message;
     286           0 :                                 tsql_handle_message(tds_get_ctx(tds), tds, &msg);
     287             :                         }
     288             :                 }
     289          20 :                 if (opt_flags & OPT_TIMER) {
     290             :                         TDSMESSAGE msg;
     291           0 :                         gettimeofday(&stop, NULL);
     292           0 :                         sprintf(message, "Total time for processing %d rows: %ld msecs\n",
     293           0 :                                 rows, (long) ((stop.tv_sec - start.tv_sec) * 1000) + ((stop.tv_usec - start.tv_usec) / 1000));
     294             : 
     295           0 :                         memset(&msg, 0, sizeof(TDSMESSAGE));
     296           0 :                         msg.server = "tsql";
     297           0 :                         msg.message = message;
     298           0 :                         tsql_handle_message(tds_get_ctx(tds), tds, &msg);
     299             :                 }
     300             :         }
     301             :         return 0;
     302             : }
     303             : 
     304             : static void
     305             : tsql_print_usage(const char *progname)
     306             : {
     307           0 :         fprintf(stderr,
     308             :                 "Usage: %s [-a <appname>] [-S <server> | -H <hostname> -p <port>] -U <username> [-P <password>] [-I <config file>] [-o <options>] [-t delim] [-r delim] [-D database]\n"
     309             :                 "  or:  %s -C\n"
     310             :                 "  or:  %s -L -H <hostname>\n"
     311             :                 "If -C is specified just print configuration and exit.\n"
     312             :                 "If -L is specified with a host name (-H) instances found are printed.\n"
     313             :                 "  -a  specify application name\n"
     314             :                 "  -S  specify server entry in freetds.conf to connect\n"
     315             :                 "  -H  specify hostname to connect\n"
     316             :                 "  -p  specify port to connect to\n"
     317             :                 "  -U  specify username to use\n"
     318             :                 "  -P  specify password to use\n"
     319             :                 "  -D  specify database name to use\n"
     320             :                 "  -I  specify old configuration file (called interface) to use\n"
     321             :                 "  -J  specify character set to use\n"
     322             :                 "  -v  verbose mode\n"
     323             :                 "-o options:\n"
     324             :                 "\tf\tDo not print footer\n"
     325             :                 "\th\tDo not print header\n"
     326             :                 "\tt\tPrint time information\n"
     327             :                 "\tv\tPrint TDS version\n"
     328             :                 "\tq\tQuiet\n\n"
     329             :                 "\tDelimiters can be multi-char strings appropriately escaped for your shell.\n"
     330             :                 "\tDefault column delimitor is <tab>; default row delimiter is <newline>\n",
     331             :                 progname, progname, progname);
     332             : }
     333             : 
     334             : static void
     335             : reset_getopt(void)
     336             : {
     337             : #ifdef HAVE_GETOPT_OPTRESET
     338             :         optreset = 1;
     339             :         optind = 1;
     340             : #else
     341          10 :         optind = 0;
     342             : #endif
     343             : }
     344             : 
     345             : /*
     346             :  * The 'GO' command may be followed by options that apply to the batch.
     347             :  * If they don't appear to be right, assume the letters "go" are part of the
     348             :  * SQL, not a batch separator.  
     349             :  */
     350             : static int
     351          10 : get_opt_flags(char *s, int *opt_flags)
     352             : {
     353             :         char **argv;
     354             :         int argc;
     355             :         int opt;
     356             : 
     357             :         /* make sure we have enough elements */
     358          10 :         assert(s && opt_flags);
     359          10 :         argv = tds_new0(char*, strlen(s) + 2);
     360          10 :         if (!argv)
     361             :                 return 0;
     362             : 
     363             :         /* parse the command line and assign to argv */
     364          10 :         for (argc=0; (argv[argc] = strtok(s, " ")) != NULL; argc++)
     365          10 :                 s = NULL;
     366             : 
     367          10 :         *opt_flags = 0;
     368             :         reset_getopt();
     369          10 :         opterr = 0;             /* suppress error messages */
     370          20 :         while ((opt = getopt(argc, argv, "fhLqtv")) != -1) {
     371           0 :                 switch (opt) {
     372           0 :                 case 'f':
     373           0 :                         *opt_flags |= OPT_NOFOOTER;
     374           0 :                         break;
     375           0 :                 case 'h':
     376           0 :                         *opt_flags |= OPT_NOHEADER;
     377           0 :                         break;
     378           0 :                 case 't':
     379           0 :                         *opt_flags |= OPT_TIMER;
     380           0 :                         break;
     381           0 :                 case 'v':
     382           0 :                         *opt_flags |= OPT_VERSION;
     383           0 :                         break;
     384           0 :                 case 'q':
     385           0 :                         *opt_flags |= OPT_QUIET;
     386           0 :                         break;
     387           0 :                 default:
     388           0 :                         fprintf(stderr, "Warning: invalid option '%s' found: \"go\" treated as simple SQL\n", argv[optind-1]);
     389           0 :                         free(argv);
     390           0 :                         return 0;
     391             :                 }
     392             :         }
     393             :         
     394          10 :         free(argv);
     395          10 :         return 1;
     396             : }
     397             : 
     398             : static int
     399           0 : get_default_instance_port(const char hostname[])
     400             : {
     401             :         int port;
     402             :         struct addrinfo *addr;
     403             :         
     404           0 :         if ((addr = tds_lookup_host(hostname)) == NULL)
     405             :                 return 0;
     406             : 
     407           0 :         port = tds7_get_instance_port(addr, "MSSQLSERVER");
     408             : 
     409           0 :         freeaddrinfo(addr);
     410             :         
     411           0 :         return port;
     412             : }
     413             : 
     414             : #if !defined(LC_ALL)
     415             : # define LC_ALL 0
     416             : #endif
     417             : 
     418             : static const char *
     419             : yes_no(bool value)
     420             : {
     421           0 :         return value ? "yes" : "no";
     422             : }
     423             : 
     424             : static void
     425          12 : populate_login(TDSLOGIN * login, int argc, char **argv)
     426             : {
     427             :         const TDS_COMPILETIME_SETTINGS *settings;
     428          12 :         char *hostname = NULL, *servername = NULL;
     429          12 :         char *username = NULL, *password = NULL;
     430          12 :         char *confile = NULL;
     431          12 :         const char *appname = "TSQL";
     432          12 :         int opt, port=0, use_domain_login=0;
     433          12 :         char *charset = NULL;
     434          12 :         char *opt_flags_str = NULL;
     435             : 
     436          60 :         while ((opt = getopt(argc, argv, "a:H:S:I:J:P:U:p:Co:t:r:D:Lv")) != -1) {
     437          36 :                 switch (opt) {
     438           0 :                 case 'a':
     439           0 :                         appname = optarg;
     440           0 :                         break;
     441           0 :                 case 't':
     442           0 :                         opt_col_term = optarg;
     443           0 :                         break;
     444           0 :                 case 'r':
     445           0 :                         opt_row_term = optarg;
     446           0 :                         break;
     447           0 :                 case 'D':
     448           0 :                         opt_default_db = optarg;
     449           0 :                         break;
     450           0 :                 case 'o':
     451           0 :                         opt_flags_str = optarg;
     452           0 :                         break;
     453           0 :                 case 'H':
     454           0 :                         free(hostname);
     455           0 :                         hostname = strdup(optarg);
     456           0 :                         break;
     457          12 :                 case 'S':
     458          12 :                         free(servername);
     459          12 :                         servername = strdup(optarg);
     460          12 :                         break;
     461          12 :                 case 'U':
     462          12 :                         free(username);
     463          12 :                         username = strdup(optarg);
     464          12 :                         break;
     465          12 :                 case 'P':
     466          12 :                         free(password);
     467          12 :                         password = tds_getpassarg(optarg);
     468          12 :                         break;
     469           0 :                 case 'I':
     470           0 :                         free(confile);
     471           0 :                         confile = strdup(optarg);
     472           0 :                         break;
     473           0 :                 case 'J':
     474           0 :                         free(charset);
     475           0 :                         charset = strdup(optarg);
     476           0 :                         break;
     477           0 :                 case 'p':
     478           0 :                         port = atoi(optarg);
     479           0 :                         break;
     480           0 :                 case 'L':
     481           0 :                         global_opt_flags |= OPT_INSTANCES;
     482           0 :                         break;
     483           0 :                 case 'v':
     484           0 :                         global_opt_flags |= OPT_VERBOSE;
     485           0 :                         break;
     486           0 :                 case 'C':
     487           0 :                         settings = tds_get_compiletime_settings();
     488           0 :                         printf("%s\n"
     489             :                                "%35s: %s\n"
     490             :                                "%35s: %" tdsPRIdir "\n"
     491             :                                "%35s: %s\n"
     492             :                                "%35s: %s\n"
     493             :                                "%35s: %s\n"
     494             :                                "%35s: %s\n"
     495             :                                "%35s: %s\n"
     496             :                                "%35s: %s\n"
     497             :                                "%35s: %s\n"
     498             :                                "%35s: %s\n"
     499             :                                "%35s: %s\n"
     500             :                                "%35s: %s\n"
     501             :                                "%35s: %s\n"
     502             :                                "%35s: %s\n",
     503             :                                "Compile-time settings (established with the \"configure\" script)",
     504             :                                "Version", settings->freetds_version,
     505             :                                "freetds.conf directory", settings->sysconfdir,
     506             :                                /* settings->last_update */
     507           0 :                                "MS db-lib source compatibility", yes_no(settings->msdblib),
     508           0 :                                "Sybase binary compatibility", yes_no(settings->sybase_compat),
     509           0 :                                "Thread safety", yes_no(settings->threadsafe),
     510           0 :                                "iconv library", yes_no(settings->libiconv),
     511             :                                "TDS version", settings->tdsver,
     512           0 :                                "iODBC", yes_no(settings->iodbc),
     513           0 :                                "unixodbc", yes_no(settings->unixodbc),
     514           0 :                                "SSPI \"trusted\" logins", yes_no(settings->sspi),
     515           0 :                                "Kerberos", yes_no(settings->kerberos),
     516           0 :                                "OpenSSL", yes_no(settings->openssl),
     517           0 :                                "GnuTLS", yes_no(settings->gnutls),
     518           0 :                                "MARS", yes_no(settings->mars));
     519           0 :                         tds_free_login(login);
     520           0 :                         exit(0);
     521             :                         break;
     522           0 :                 default:
     523           0 :                         tsql_print_usage(basename(argv[0]));
     524           0 :                         exit(1);
     525             :                         break;
     526             :                 }
     527             :         }
     528             : 
     529          12 :         if (opt_flags_str != NULL) {
     530           0 :                 char *minus_flags = tds_new(char, strlen(opt_flags_str) + 5);
     531           0 :                 if (minus_flags != NULL) {
     532           0 :                         strcpy(minus_flags, "go -");
     533           0 :                         strcat(minus_flags, opt_flags_str);
     534           0 :                         get_opt_flags(minus_flags, &global_opt_flags);
     535           0 :                         free(minus_flags);
     536             :                 }
     537             :         }
     538             : 
     539          12 :         if ((global_opt_flags & OPT_INSTANCES) && hostname) {
     540             :                 struct addrinfo *addr;
     541           0 :                 tds_dir_char *filename = tds_dir_getenv(TDS_DIR("TDSDUMP"));
     542             : 
     543           0 :                 if (filename) {
     544           0 :                         size_t len = tds_dir_len(filename) + 12;
     545           0 :                         tds_dir_char *path = tds_new(tds_dir_char, len);
     546           0 :                         if (!path)
     547           0 :                                 exit(1);
     548           0 :                         tds_dir_snprintf(path, len, TDS_DIR("%s.instances"), filename);
     549           0 :                         tdsdump_open(path);
     550           0 :                         free(path);
     551             :                 }
     552           0 :                 if ((addr = tds_lookup_host(hostname)) != NULL) {
     553           0 :                         tds7_get_instance_ports(stderr, addr);
     554           0 :                         freeaddrinfo(addr);
     555             :                 }
     556           0 :                 tdsdump_close();
     557           0 :                 exit(0);
     558             :         }
     559             : 
     560             :         /* validate parameters */
     561          12 :         if (!servername && !hostname) {
     562           0 :                 fprintf(stderr, "%s: error: Missing argument -S or -H\n", argv[0]);
     563           0 :                 exit(1);
     564             :         }
     565          12 :         if (hostname && !port) {
     566             :                 /*
     567             :                  * TODO: It would be convenient to have a function that looks up a reasonable port based on:
     568             :                  *      - TDSPORT environment variable
     569             :                  *      - config files
     570             :                  *      - get_default_instance_port
     571             :                  *      - TDS version
     572             :                  *      in that order. 
     573             :                  */
     574           0 :                 if (!QUIET) {
     575           0 :                         printf("Missing argument -p, looking for default instance ... ");
     576             :                 }
     577           0 :                 if (0 == (port = get_default_instance_port(hostname))) {
     578           0 :                         fprintf(stderr, "%s: no default port provided by host %s\n", argv[0], hostname);
     579           0 :                         exit(1);
     580             :                 } 
     581           0 :                 if (!QUIET)
     582           0 :                         printf("found default instance, port %d\n", port);
     583             :                 
     584             :         }
     585             :         /* A NULL username indicates a domain (trusted) login */
     586          12 :         if (!username) {
     587           0 :                 username = tds_new0(char, 1);
     588           0 :                 if (!username) {
     589           0 :                         fprintf(stderr, "Could not allocate memory for username\n");
     590           0 :                         exit(1);
     591             :                 }
     592             :                 use_domain_login = 1;
     593             :         }
     594          12 :         if (!password) {
     595           0 :                 password = tds_new0(char, 128);
     596           0 :                 if (!password) {
     597           0 :                         fprintf(stderr, "Could not allocate memory for password\n");
     598           0 :                         exit(1);
     599             :                 }
     600           0 :                 if (!use_domain_login)
     601           0 :                         readpassphrase("Password: ", password, 128, RPP_ECHO_OFF);
     602             :         }
     603          12 :         if (!opt_col_term) {
     604           0 :                 fprintf(stderr, "%s: missing delimiter for -t (check escaping)\n", argv[0]);
     605           0 :                 exit(1);
     606             :         }
     607          12 :         if (!opt_row_term) {
     608           0 :                 fprintf(stderr, "%s: missing delimiter for -r (check escaping)\n", argv[0]);
     609           0 :                 exit(1);
     610             :         }
     611             : 
     612             :         /* all validated, let's do it */
     613          12 :         if (!tds_set_user(login, username)
     614          12 :             || !tds_set_app(login, appname)
     615          12 :             || !tds_set_library(login, "TDS-Library")
     616          12 :             || !tds_set_language(login, "us_english")
     617          12 :             || !tds_set_passwd(login, password))
     618             :                 goto out_of_memory;
     619          12 :         if (charset && !tds_set_client_charset(login, charset))
     620             :                 goto out_of_memory;
     621             : 
     622             :         /* if it's a servername */
     623          12 :         if (servername) {
     624          12 :                 if (!tds_set_server(login, servername))
     625             :                         goto out_of_memory;
     626          12 :                 if (confile) {
     627           0 :                         tds_set_interfaces_file_loc(confile);
     628             :                 }
     629             :                 /* else we specified hostname/port */
     630             :         } else {
     631           0 :                 if (!tds_set_server(login, hostname))
     632             :                         goto out_of_memory;
     633           0 :                 tds_set_port(login, port);
     634             :         }
     635             : 
     636             :         memset(password, 0, strlen(password));
     637             : 
     638             :         /* free up all the memory */
     639          12 :         free(confile);
     640          12 :         free(hostname);
     641          12 :         free(username);
     642          12 :         free(password);
     643          12 :         free(servername);
     644          12 :         free(charset);
     645          12 :         return;
     646             : 
     647           0 : out_of_memory:
     648           0 :         fprintf(stderr, "%s: out of memory\n", argv[0]);
     649           0 :         exit(1);
     650             : }
     651             : 
     652             : static int
     653          22 : tsql_handle_message(const TDSCONTEXT * context TDS_UNUSED, TDSSOCKET * tds TDS_UNUSED, TDSMESSAGE * msg)
     654             : {
     655          22 :         if (msg->msgno == 0) {
     656           0 :                 fprintf(stderr, "%s\n", msg->message);
     657           0 :                 return 0;
     658             :         }
     659             : 
     660          22 :         switch (msg->msgno) {
     661          18 :         case 5701:      /* changed_database */
     662             :         case 5703:      /* changed_language */
     663             :         case 20018:     /* The @optional_command_line is too long */
     664          18 :                 if (VERBOSE)
     665           0 :                         fprintf(stderr, "%s\n", msg->message);
     666             :                 break;
     667           4 :         default:
     668          12 :                 fprintf(stderr, "Msg %d (severity %d, state %d) from %s", 
     669           8 :                         msg->msgno, msg->severity, msg->state, msg->server);
     670           4 :                 if (msg->proc_name && strlen(msg->proc_name))
     671           0 :                         fprintf(stderr, ", Procedure %s", msg->proc_name);
     672           4 :                 if (msg->line_number > 0)
     673           0 :                         fprintf(stderr, " Line %d", msg->line_number);
     674           4 :                 fprintf(stderr, ":\n\t\"%s\"\n", msg->message);
     675           4 :                 break;
     676             :         }
     677             : 
     678             :         return 0;
     679             : }
     680             : 
     681             : static int      /* error from library, not message from server */
     682           2 : tsql_handle_error(const TDSCONTEXT * context TDS_UNUSED, TDSSOCKET * tds TDS_UNUSED, TDSMESSAGE * msg)
     683             : {
     684           2 :         fprintf(stderr, "Error %d (severity %d):\n\t%s\n", msg->msgno, msg->severity, msg->message);
     685           2 :         if (0 != msg->oserr) {
     686           0 :                 fprintf(stderr, "\tOS error %d, \"%s\"\n", msg->oserr, strerror(msg->oserr));
     687             :         }
     688           2 :         return TDS_INT_CANCEL;
     689             : }
     690             : 
     691             : static void
     692           0 : slurp_input_file(char *fname, char **mybuf, size_t *bufsz, size_t *buflen, int *line)
     693             : {
     694           0 :         FILE *fp = NULL;
     695             :         register char *n;
     696             :         char linebuf[1024];
     697           0 :         char *s = NULL;
     698             : 
     699           0 :         if ((fp = fopen(fname, "r")) == NULL) {
     700           0 :                 fprintf(stderr, "Unable to open input file '%s': %s\n", fname, strerror(errno));
     701           0 :                 return;
     702             :         }
     703           0 :         while ((s = fgets(linebuf, sizeof(linebuf), fp)) != NULL) {
     704           0 :                 while (*buflen + strlen(s) + 2 > *bufsz) {
     705           0 :                         *bufsz *= 2;
     706           0 :                         if (!TDS_RESIZE(*mybuf, *bufsz)) {
     707           0 :                                 perror("tsql: ");
     708           0 :                                 exit(1);
     709             :                         }
     710             :                 }
     711           0 :                 strcpy(*mybuf + *buflen, s);
     712           0 :                 *buflen += strlen(*mybuf + *buflen);
     713           0 :                 n = strrchr(s, '\n');
     714           0 :                 if (n != NULL)
     715           0 :                         *n = '\0';
     716           0 :                 tsql_add_history(s);
     717           0 :                 (*line)++;
     718             :         }
     719           0 :         fclose(fp);
     720             : }
     721             : 
     722             : static void
     723           0 : print_instance_data(TDSLOGIN *login) 
     724             : {
     725           0 :         if (!login)
     726             :                 return;
     727             :         
     728           0 :         if (!tds_dstr_isempty(&login->instance_name))
     729           0 :                 printf("connecting to instance %s on port %d\n", tds_dstr_cstr(&login->instance_name), login->port);
     730             : }
     731             : 
     732             : #if defined(HAVE_ALARM) && !defined(_WIN32)
     733             : static void
     734           0 : count_alarm(int s TDS_UNUSED)
     735             : {
     736             :         static int count = 0;
     737             :         char buf[64];
     738             : 
     739             :         /* print the counter, do not use stderr as may be locked! */
     740           0 :         sprintf(buf, "\r%2d", ++count);
     741           0 :         write(STDERR_FILENO, buf, strlen(buf));
     742             : 
     743           0 :         alarm(1);
     744           0 : }
     745             : #endif
     746             : 
     747             : int
     748          12 : main(int argc, char **argv)
     749             : {
     750          12 :         char *s = NULL, *s2 = NULL, *cmd = NULL;
     751             :         char prompt[20];
     752          12 :         int line = 0;
     753             :         char *mybuf;
     754          12 :         size_t bufsz = 4096;
     755          12 :         size_t buflen = 0;
     756             :         TDSSOCKET *tds;
     757             :         TDSLOGIN *login;
     758             :         TDSCONTEXT *context;
     759             :         TDSLOGIN *connection;
     760          12 :         int opt_flags = 0;
     761          12 :         const char *locale = NULL;
     762          12 :         const char *charset = NULL;
     763             : 
     764          12 :         istty = isatty(0);
     765             : 
     766             :         if (INITSOCKET()) {
     767             :                 fprintf(stderr, "Unable to initialize sockets\n");
     768             :                 return 1;
     769             :         }
     770             : 
     771          12 :         setlocale(LC_ALL, "");
     772             : 
     773             :         /* grab a login structure */
     774          12 :         login = tds_alloc_login(1);
     775          12 :         if (!login) {
     776           0 :                 fprintf(stderr, "login cannot be null\n");
     777           0 :                 return 1;
     778             :         }
     779             : 
     780             :         /* process all the command line args into the login structure */
     781          12 :         populate_login(login, argc, argv);
     782             : 
     783          12 :         context = tds_alloc_context(NULL);
     784          12 :         if (!context) {
     785           0 :                 tds_free_login(login);
     786           0 :                 fprintf(stderr, "context cannot be null\n");
     787           0 :                 return 1;
     788             :         }
     789          12 :         if (context->locale && !context->locale->datetime_fmt) {
     790             :                 /* set default in case there's no locale file */
     791           0 :                 context->locale->datetime_fmt = strdup(STD_DATETIME_FMT);
     792             :         }
     793             : 
     794          12 :         context->msg_handler = tsql_handle_message;
     795          12 :         context->err_handler = tsql_handle_error;
     796             : 
     797             :         /* Try to open a connection */
     798          12 :         tds = tds_alloc_socket(context, 512);
     799          12 :         assert(tds);
     800          12 :         tds_set_parent(tds, NULL);
     801          12 :         connection = tds_read_config_info(tds, login, context->locale);
     802          12 :         if (!connection)
     803             :                 return 1;
     804             : 
     805          12 :         locale = setlocale(LC_ALL, NULL);
     806             : 
     807             : #if HAVE_LOCALE_CHARSET
     808             :         charset = locale_charset();
     809             : #endif
     810             : #if HAVE_NL_LANGINFO && defined(CODESET)
     811             :         if (!charset)
     812          12 :                 charset = nl_langinfo(CODESET);
     813             : #endif
     814             : 
     815          12 :         if (locale)
     816          12 :                 if (!QUIET) printf("locale is \"%s\"\n", locale);
     817          12 :         if (charset) {
     818          12 :                 if (!QUIET) printf("locale charset is \"%s\"\n", charset);
     819             :         }
     820             :         
     821          24 :         if (tds_dstr_isempty(&connection->client_charset)) {
     822           0 :                 if (!charset)
     823           0 :                         charset = "ISO-8859-1";
     824             : 
     825           0 :                 if (!tds_set_client_charset(login, charset))
     826             :                         return 1;
     827           0 :                 if (!tds_dstr_dup(&connection->client_charset, &login->client_charset))
     828             :                         return 1;
     829             :         }
     830          24 :         if (!QUIET) printf("using default charset \"%s\"\n", tds_dstr_cstr(&connection->client_charset));
     831             : 
     832          12 :         if (opt_default_db) {
     833           0 :                 if (!tds_dstr_copy(&connection->database, opt_default_db))
     834             :                         return 1;
     835           0 :                 if (!QUIET) fprintf(stderr, "Setting %s as default database in login packet\n", opt_default_db);
     836             :         }
     837             : 
     838             :         /* 
     839             :          * If we're able to establish an ip address for the server, we'll try to connect to it. 
     840             :          * If that machine is currently unreachable, show a timer connecting to the server. 
     841             :          */
     842             : #if defined(HAVE_ALARM) && !defined(_WIN32)
     843          12 :         if (connection && !QUIET) {
     844          12 :                 signal(SIGALRM, count_alarm);
     845          12 :                 fflush(stderr);
     846          12 :                 alarm(1);
     847             :         }
     848             : #endif
     849          12 :         if (!connection || TDS_FAILED(tds_connect_and_login(tds, connection))) {
     850           2 :                 if (VERBOSE)
     851           0 :                         print_instance_data(connection);
     852           2 :                 tds_free_socket(tds);
     853           2 :                 tds_free_login(login);
     854           2 :                 tds_free_context(context);
     855           2 :                 fprintf(stderr, "There was a problem connecting to the server\n");
     856           2 :                 exit(1);
     857             :         }
     858             : 
     859             : #if defined(HAVE_ALARM) && !defined(_WIN32)
     860          10 :         if (!QUIET) {
     861          10 :                 alarm(0);
     862          10 :                 signal(SIGALRM, SIG_DFL);
     863          10 :                 fprintf(stderr, "\r");
     864             :         }
     865             : #endif
     866             : 
     867          10 :         if (VERBOSE) 
     868           0 :                 print_instance_data(connection);
     869          10 :         tds_free_login(connection);
     870             :         /* give the buffer an initial size */
     871          10 :         bufsz = 4096;
     872          10 :         mybuf = tds_new(char, bufsz);
     873          10 :         if (!mybuf) {
     874           0 :                 fprintf(stderr, "Could not allocate memory for mybuf\n");
     875           0 :                 return 1;
     876             :         }
     877          10 :         mybuf[0] = '\0';
     878          10 :         buflen = 0;
     879             : 
     880             : #if defined(HAVE_READLINE) && HAVE_RL_INHIBIT_COMPLETION
     881          10 :         rl_inhibit_completion = 1;
     882             : #endif
     883             : 
     884          30 :         for (s=NULL, s2=NULL; ; free(s), free(s2), s2=NULL) {
     885          50 :                 sprintf(prompt, "%d> ", ++line);
     886          30 :                 s = tsql_readline(QUIET ? NULL : prompt);
     887          30 :                 if (s == NULL) {
     888           0 :                         if (buflen)
     889           0 :                                 do_query(tds, mybuf, global_opt_flags);
     890             :                         break;
     891             :                 }
     892             : 
     893             :                 /* 
     894             :                  * 'GO' is special only at the start of a line
     895             :                  *  The rest of the line may include options that apply to the batch, 
     896             :                  *  and perhaps whitespace.  
     897             :                  */
     898          30 :                 if (0 == strncasecmp(s, "go", 2) && (strlen(s) == 2 || TDS_ISSPACE(s[2]))) {
     899          10 :                         char *go_line = strdup(s);
     900          10 :                         assert(go_line);
     901          10 :                         line = 0;
     902          10 :                         if (get_opt_flags(go_line, &opt_flags)) {
     903          10 :                                 free(go_line);
     904          10 :                                 opt_flags ^= global_opt_flags;
     905          10 :                                 do_query(tds, mybuf, opt_flags);
     906          10 :                                 mybuf[0] = '\0';
     907          10 :                                 buflen = 0;
     908          10 :                                 continue;
     909             :                         }
     910           0 :                         free(go_line);
     911             :                 }
     912             :                 
     913             :                 /* skip leading whitespace */
     914          20 :                 if ((s2 = strdup(s)) == NULL) { /* copy to mangle with strtok() */
     915           0 :                         perror("tsql: ");
     916           0 :                         exit(1);
     917             :                 }
     918             :                 
     919          20 :                 if ((cmd = strtok(s2, " \t")) == NULL)
     920           0 :                         cmd = "";
     921             : 
     922          20 :                 if (!strcasecmp(cmd, "exit") || !strcasecmp(cmd, "quit") || !strcasecmp(cmd, "bye"))
     923             :                         break;
     924          10 :                 if (!strcasecmp(cmd, "version")) {
     925           0 :                         tds_version(tds->conn, mybuf);
     926           0 :                         printf("using TDS version %s\n", mybuf);
     927           0 :                         line = 0;
     928           0 :                         mybuf[0] = '\0';
     929           0 :                         buflen = 0;
     930           0 :                         continue;
     931             :                 }
     932          10 :                 if (!strcasecmp(cmd, "reset")) {
     933           0 :                         line = 0;
     934           0 :                         mybuf[0] = '\0';
     935           0 :                         buflen = 0;
     936          10 :                 } else if (!strcasecmp(cmd, ":r")) {
     937           0 :                         slurp_input_file(strtok(NULL, " \t"), &mybuf, &bufsz, &buflen, &line);
     938             :                 } else {
     939          10 :                         while (buflen + strlen(s) + 2 > bufsz) {
     940           0 :                                 bufsz *= 2;
     941           0 :                                 if (!TDS_RESIZE(mybuf, bufsz)) {
     942           0 :                                         perror("tsql: ");
     943           0 :                                         exit(1);
     944             :                                 }
     945             :                         }
     946          10 :                         tsql_add_history(s);
     947          10 :                         strcpy(mybuf + buflen, s);
     948             :                         /* preserve line numbering for the parser */
     949          10 :                         strcat(mybuf + buflen, "\n");
     950          10 :                         buflen += strlen(mybuf + buflen);
     951             :                 }
     952             :         }
     953             : 
     954             :         /* close up shop */
     955          10 :         free(mybuf);
     956          10 :         tds_close_socket(tds);
     957          10 :         tds_free_socket(tds);
     958          10 :         tds_free_login(login);
     959          10 :         tds_free_context(context);
     960             :         DONESOCKET();
     961             : 
     962          10 :         return 0;
     963             : }

Generated by: LCOV version 1.13