LCOV - code coverage report
Current view: top level - src/apps - freebcp.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 153 372 41.1 %
Date: 2026-07-19 14:02:14 Functions: 11 14 78.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) 2011  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 <stdio.h>
      24             : #include <ctype.h>
      25             : 
      26             : #if HAVE_ERRNO_H
      27             : #include <errno.h>
      28             : #endif /* HAVE_ERRNO_H */
      29             : 
      30             : #if HAVE_STDLIB_H
      31             : #include <stdlib.h>
      32             : #endif /* HAVE_STDLIB_H */
      33             : 
      34             : /* These should be in stdlib */
      35             : #ifndef EXIT_SUCCESS
      36             : #define EXIT_SUCCESS 0
      37             : #endif
      38             : #ifndef EXIT_FAILURE
      39             : #define EXIT_FAILURE 1
      40             : #endif
      41             : 
      42             : #if HAVE_STRING_H
      43             : #include <string.h>
      44             : #endif /* HAVE_STRING_H */
      45             : 
      46             : #if HAVE_STRINGS_H
      47             : #include <strings.h>
      48             : #endif /* HAVE_STRINGS_H */
      49             : 
      50             : #if HAVE_UNISTD_H
      51             : #include <unistd.h>
      52             : #endif
      53             : 
      54             : #if HAVE_LOCALE_H
      55             : #include <locale.h>
      56             : #endif
      57             : 
      58             : #include <sybfront.h>
      59             : #include <sybdb.h>
      60             : 
      61             : #include <freetds/macros.h>
      62             : #include <freetds/bool.h>
      63             : #include <freetds/version.h>
      64             : #include <freetds/utils.h>
      65             : #include <freetds/utils/path.h>
      66             : #include <freetds/replacements.h>
      67             : 
      68             : #include "freebcp.h"
      69             : 
      70             : enum
      71             : {
      72             :         BCPFORMAT_NONE, BCPFORMAT_CHARACTER, BCPFORMAT_NATIVE, BCPFORMAT_FORMATTED
      73             : };
      74             : typedef int BCPFORMAT;
      75             : 
      76             : int tdsdump_open(const char *filename);
      77             : 
      78             : static void pusage(void);
      79             : static int process_parameters(int, char **, BCPPARAMDATA *);
      80             : static int unescape(char arg[]);
      81             : static int login_to_database(BCPPARAMDATA * pdata, DBPROCESS ** pdbproc);
      82             : 
      83             : static int setoptions(DBPROCESS * dbproc, BCPPARAMDATA * params);
      84             : static BCPFORMAT get_format(BCPPARAMDATA * params);
      85             : static int file_process(BCPPARAMDATA * pdata, DBPROCESS * dbproc, DBINT dir);
      86             : static int err_handler(DBPROCESS * dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr);
      87             : static int msg_handler(DBPROCESS * dbproc TDS_UNUSED, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname,
      88             :                        char *procname, int line);
      89             : static int set_bcp_hints(BCPPARAMDATA * pdata, DBPROCESS * pdbproc);
      90             : static void bcpparamdata_free(BCPPARAMDATA * params);
      91             : 
      92             : int
      93          10 : main(int argc, char **argv)
      94             : {
      95             :         BCPPARAMDATA params;
      96             :         DBPROCESS *dbproc;
      97          10 :         int ok = FALSE;
      98             : 
      99          10 :         setlocale(LC_ALL, "");
     100             : 
     101             : #ifdef __VMS
     102             :         /* Convert VMS-style arguments to Unix-style */
     103             :         parse_vms_args(&argc, &argv);
     104             : #endif
     105             : 
     106          10 :         memset(&params, '\0', sizeof(params));
     107             : 
     108          10 :         params.textsize = 4096; /* our default text size is 4K */
     109             : 
     110          10 :         if (process_parameters(argc, argv, &params) == FALSE) {
     111           0 :                 exit(EXIT_FAILURE);
     112             :         }
     113          10 :         if (getenv("FREEBCP")) {
     114           0 :                 fprintf(stderr, "User name: \"%s\"\n", params.user);
     115             :         }
     116             : 
     117             : 
     118          10 :         if (login_to_database(&params, &dbproc) == FALSE) {
     119           0 :                 exit(EXIT_FAILURE);
     120             :         }
     121             : 
     122          10 :         if (!setoptions(dbproc, &params))
     123             :                 return FALSE;
     124             : 
     125          10 :         ok = file_process(&params, dbproc, params.direction);
     126             : 
     127          10 :         dbclose(dbproc);
     128          10 :         dbexit();
     129          10 :         bcpparamdata_free(&params);
     130             : 
     131          10 :         return (ok == TRUE) ? EXIT_SUCCESS : EXIT_FAILURE;
     132             : }
     133             : 
     134             : static BCPFORMAT
     135             : get_format(BCPPARAMDATA *params)
     136             : {
     137          10 :         if (params->cflag)
     138             :                 return BCPFORMAT_CHARACTER;
     139             : 
     140           0 :         if (params->nflag)
     141             :                 return BCPFORMAT_NATIVE;
     142             : 
     143           0 :         if (params->fflag)
     144             :                 return BCPFORMAT_FORMATTED;
     145             : 
     146             :         return BCPFORMAT_NONE;
     147             : }
     148             : 
     149             : static int
     150           0 : unescape_hex(char *arg)
     151             : {
     152             :         char *buf;
     153             :         size_t len;
     154             :         DBINT out_len;
     155             : 
     156           0 :         if (strncasecmp(arg, "0x", 2) != 0)
     157             :                 return -1;
     158             : 
     159           0 :         len = strlen(arg);
     160           0 :         buf = xstrdup(arg);
     161           0 :         out_len = dbconvert(NULL, SYBVARCHAR, (void *) arg, len, SYBVARBINARY, (void *) buf, (DBINT) len);
     162           0 :         if (out_len < 0) {
     163           0 :                 free(buf);
     164           0 :                 return -1;
     165             :         }
     166             : 
     167             :         /* As documented we stop at the first NUL character */
     168           0 :         buf[out_len] = 0;
     169           0 :         out_len = (int) strlen(buf);
     170             : 
     171           0 :         memcpy(arg, buf, out_len);
     172           0 :         free(buf);
     173           0 :         return out_len;
     174             : }
     175             : 
     176             : static int
     177           0 : unescape(char arg[])
     178             : {
     179           0 :         char *p = arg, *next;
     180             :         char escaped;
     181             :         int hex_res;
     182             : 
     183           0 :         hex_res = unescape_hex(arg);
     184           0 :         if (hex_res >= 0)
     185             :                 return hex_res;
     186             : 
     187           0 :         while ((next = strchr(p, '\\')) != NULL) {
     188             : 
     189           0 :                 p = next;
     190             : 
     191           0 :                 switch (p[1]) {
     192             :                 case '0':
     193             :                         escaped = '\0';
     194             :                         break;
     195           0 :                 case 't':
     196           0 :                         escaped = '\t';
     197           0 :                         break;
     198           0 :                 case 'r':
     199           0 :                         escaped = '\r';
     200           0 :                         break;
     201           0 :                 case 'n':
     202             : #ifdef _WIN32
     203             :                         memcpy(p, "\r\n", 2);
     204             :                         continue;
     205             : #else
     206           0 :                         escaped = '\n';
     207             : #endif
     208           0 :                         break;
     209           0 :                 case '\\':
     210           0 :                         escaped = '\\';
     211           0 :                         break;
     212           0 :                 default:
     213           0 :                         ++p;
     214           0 :                         continue;
     215             :                 }
     216             : 
     217             :                 /* Overwrite the backslash with the intended character, and shift everything down one */
     218           0 :                 *p++ = escaped;
     219           0 :                 memmove(p, p+1, 1 + strlen(p+1));
     220             :         }
     221           0 :         return strchr(p, 0) - arg;
     222             : }
     223             : 
     224             : static int
     225          10 : process_parameters(int argc, char **argv, BCPPARAMDATA *pdata)
     226             : {
     227             :         extern char *optarg;
     228             :         extern int optind;
     229             :         extern int optopt;
     230             : 
     231             :         int ch;
     232             : 
     233          10 :         if (argc < 6) {
     234           0 :                 pusage();
     235           0 :                 return (FALSE);
     236             :         }
     237             : 
     238             :         /*
     239             :          * Set some defaults and read the table, file, and direction arguments.
     240             :          */
     241          10 :         pdata->firstrow = 0;
     242          10 :         pdata->lastrow = 0;
     243          10 :         pdata->batchsize = 1000;
     244          10 :         pdata->maxerrors = 10;
     245             : 
     246             :         /* argument 1 - the database object */
     247          10 :         pdata->dbobject = xstrdup(argv[1]);
     248             : 
     249             :         /* argument 2 - the direction */
     250          10 :         strlcpy(pdata->dbdirection, argv[2], sizeof(pdata->dbdirection));
     251             : 
     252          10 :         if (strcasecmp(pdata->dbdirection, "in") == 0) {
     253          10 :                 pdata->direction = DB_IN;
     254           0 :         } else if (strcasecmp(pdata->dbdirection, "out") == 0) {
     255           0 :                 pdata->direction = DB_OUT;
     256           0 :         } else if (strcasecmp(pdata->dbdirection, "queryout") == 0) {
     257           0 :                 pdata->direction = DB_QUERYOUT;
     258             :         } else {
     259           0 :                 fprintf(stderr, "Copy direction must be either 'in', 'out' or 'queryout'.\n");
     260           0 :                 return (FALSE);
     261             :         }
     262             : 
     263             :         /* argument 3 - the datafile name */
     264          10 :         free(pdata->hostfilename);
     265          10 :         pdata->hostfilename = xstrdup(argv[3]);
     266             : 
     267             :         /*
     268             :          * Get the rest of the arguments
     269             :          */
     270          10 :         optind = 4;             /* start processing options after table, direction, & filename */
     271          80 :         while ((ch = getopt(argc, argv, "m:f:e:F:L:b:t:r:U:P:i:I:S:h:T:A:o:O:0:C:ncEdvVD:kj")) != -1) {
     272          60 :                 switch (ch) {
     273           0 :                 case 'v':
     274             :                 case 'V':
     275           0 :                         printf("freebcp version %s\n", TDS_VERSION_NO);
     276           0 :                         return FALSE;
     277             :                         break;
     278           0 :                 case 'm':
     279           0 :                         pdata->maxerrors = atoi(optarg);
     280           0 :                         break;
     281           0 :                 case 'f':
     282           0 :                         pdata->fflag = true;
     283           0 :                         free(pdata->formatfile);
     284           0 :                         pdata->formatfile = xstrdup(optarg);
     285           0 :                         break;
     286          10 :                 case 'e':
     287          10 :                         pdata->errorfile = xstrdup(optarg);
     288          10 :                         break;
     289           0 :                 case 'F':
     290           0 :                         pdata->firstrow = atoi(optarg);
     291           0 :                         break;
     292           0 :                 case 'L':
     293           0 :                         pdata->lastrow = atoi(optarg);
     294           0 :                         break;
     295           0 :                 case 'b':
     296           0 :                         pdata->batchsize = atoi(optarg);
     297           0 :                         break;
     298           0 :                 case 'n':
     299           0 :                         pdata->nflag = true;
     300           0 :                         break;
     301          10 :                 case 'c':
     302          10 :                         pdata->cflag = true;
     303          10 :                         break;
     304           0 :                 case 'E':
     305           0 :                         pdata->Eflag = true;
     306           0 :                         break;
     307           0 :                 case 'd':
     308           0 :                         tdsdump_open("stderr");
     309           0 :                         break;
     310           0 :                 case 't':
     311           0 :                         pdata->tflag = true;
     312           0 :                         pdata->fieldterm = xstrdup(optarg);
     313           0 :                         pdata->fieldtermlen = unescape(pdata->fieldterm);
     314           0 :                         break;
     315           0 :                 case 'r':
     316           0 :                         pdata->rflag = true;
     317           0 :                         pdata->rowterm = xstrdup(optarg);
     318           0 :                         pdata->rowtermlen = unescape(pdata->rowterm);
     319           0 :                         break;
     320          10 :                 case 'U':
     321          10 :                         pdata->user = xstrdup(optarg);
     322          10 :                         break;
     323          10 :                 case 'P':
     324          10 :                         pdata->pass = tds_getpassarg(optarg);
     325          10 :                         break;
     326           0 :                 case 'i':
     327           0 :                         free(pdata->inputfile);
     328           0 :                         pdata->inputfile = xstrdup(optarg);
     329           0 :                         break;
     330           0 :                 case 'I':
     331           0 :                         free(pdata->interfacesfile);
     332           0 :                         pdata->interfacesfile = xstrdup(optarg);
     333           0 :                         break;
     334          10 :                 case 'S':
     335          10 :                         pdata->Sflag = true;
     336          10 :                         pdata->server = xstrdup(optarg);
     337          10 :                         break;
     338          10 :                 case 'D':
     339          10 :                         pdata->dbname = xstrdup(optarg);
     340          10 :                         break;
     341           0 :                 case 'h':
     342           0 :                         pdata->hint = xstrdup(optarg);
     343           0 :                         break;
     344           0 :                 case 'o':
     345           0 :                         free(pdata->outputfile);
     346           0 :                         pdata->outputfile = xstrdup(optarg);
     347           0 :                         break;
     348           0 :                 case 'O':
     349             :                 case '0':
     350           0 :                         pdata->options = xstrdup(optarg);
     351           0 :                         break;
     352           0 :                 case 'T':
     353           0 :                         pdata->textsize = atoi(optarg);
     354           0 :                         break;
     355           0 :                 case 'A':
     356           0 :                         pdata->Aflag = true;
     357           0 :                         pdata->packetsize = atoi(optarg);
     358           0 :                         break;
     359           0 :                 case 'C':
     360           0 :                         pdata->charset = xstrdup(optarg);
     361           0 :                         break;
     362           0 :                 case 'k':
     363           0 :                         pdata->ignoreDefaults = true;
     364           0 :                         break;
     365           0 :                 case 'j':
     366           0 :                         pdata->dry_run = true;
     367           0 :                         break;
     368           0 :                 case '?':
     369             :                 default:
     370           0 :                         pusage();
     371           0 :                         return (FALSE);
     372             :                 }
     373             :         }
     374             : 
     375             :         /*
     376             :          * Check for required/disallowed option combinations
     377             :          * If no username is provided, rely on domain login.
     378             :          */
     379             : 
     380             :         /* Server */
     381          10 :         if (!pdata->Sflag) {
     382           0 :                 if ((pdata->server = getenv("DSQUERY")) != NULL) {
     383           0 :                         pdata->server = xstrdup(pdata->server);   /* can be freed */
     384           0 :                         pdata->Sflag = true;
     385             :                 } else {
     386           0 :                         fprintf(stderr, "-S must be supplied.\n");
     387           0 :                         return (FALSE);
     388             :                 }
     389             :         }
     390             : 
     391             :         /* Only one of these can be specified */
     392          10 :         if (!!pdata->cflag + !!pdata->nflag + !!pdata->fflag != 1) {
     393           0 :                 fprintf(stderr, "Exactly one of options -c, -n, -f must be supplied.\n");
     394           0 :                 return (FALSE);
     395             :         }
     396             : 
     397             :         /* Character mode file: fill in default values */
     398          10 :         if (pdata->cflag) {
     399             : 
     400          10 :                 if (!pdata->tflag || !pdata->fieldterm) { /* field terminator not specified */
     401          10 :                         pdata->fieldterm = xstrdup("\t");
     402          10 :                         pdata->fieldtermlen = 1;
     403             :                 }
     404          10 :                 if (!pdata->rflag || !pdata->rowterm) {   /* row terminator not specified */
     405             : #ifdef _WIN32
     406             :                         pdata->rowterm = xstrdup("\r\n");
     407             :                         pdata->rowtermlen = 2;
     408             : #else
     409          10 :                         pdata->rowterm = xstrdup("\n");
     410          10 :                         pdata->rowtermlen = 1;
     411             : #endif
     412             :                 }
     413             :         }
     414             : 
     415             :         /* -k will be implemented on MSSQL by -hKEEP_NULLS */
     416          10 :         if (pdata->ignoreDefaults) {
     417           0 :                 if (!pdata->hint)
     418           0 :                         pdata->hint = xstrdup("KEEP_NULLS");
     419           0 :                 else if (strstr(pdata->hint, "KEEP_NULLS") == NULL) {
     420             :                         /* Append to existing hints if not already present */
     421             :                         char *hints;
     422           0 :                         int ret = asprintf(&hints, "%s,KEEP_NULLS", pdata->hint);
     423             : 
     424           0 :                         if (ret < 0) {
     425           0 :                                 fprintf(stderr, "Failed to apply -k flag to hints");
     426           0 :                                 return FALSE;
     427             :                         }
     428           0 :                         free(pdata->hint);
     429           0 :                         pdata->hint = hints;
     430             :                 }
     431             :         }
     432             : 
     433             :         /*
     434             :          * Override stdin and/or stdout if requested.
     435             :          */
     436             : 
     437             :         /* FIXME -- Since we don't implement prompting for field data types when neither -c nor -n
     438             :          * is specified, redirecting stdin doesn't do much yet.
     439             :          */
     440          10 :         if (pdata->inputfile) {
     441           0 :                 if (freopen(pdata->inputfile, "rb", stdin) == NULL) {
     442           0 :                         fprintf(stderr, "%s: unable to open %s: %s\n", "freebcp", pdata->inputfile, strerror(errno));
     443           0 :                         exit(EXIT_FAILURE);
     444             :                 }
     445             :         }
     446             : 
     447          10 :         if (pdata->outputfile) {
     448           0 :                 if (freopen(pdata->outputfile, "wb", stdout) == NULL) {
     449           0 :                         fprintf(stderr, "%s: unable to open %s: %s\n", "freebcp", pdata->outputfile, strerror(errno));
     450           0 :                         exit(EXIT_FAILURE);
     451             :                 }
     452             :         }
     453             : 
     454             :         return (TRUE);
     455             : 
     456             : }
     457             : 
     458             : static int
     459          10 : process_Eflag(BCPPARAMDATA *pdata, DBPROCESS *dbproc)
     460             : {
     461          10 :         if (pdata->Eflag) {
     462             : 
     463           0 :                 bcp_control(dbproc, BCPKEEPIDENTITY, 1);
     464             : 
     465           0 :                 if (dbfcmd(dbproc, "set identity_insert %s on", pdata->dbobject) == FAIL) {
     466           0 :                         fprintf(stderr, "dbfcmd failed\n");
     467             :                         return FALSE;
     468             :                 }
     469             : 
     470           0 :                 if (dbsqlexec(dbproc) == FAIL) {
     471           0 :                         fprintf(stderr, "dbsqlexec failed\n");
     472             :                         return FALSE;
     473             :                 }
     474             : 
     475           0 :                 while (NO_MORE_RESULTS != dbresults(dbproc))
     476           0 :                         continue;
     477             :         }
     478             :         return TRUE;
     479             : }
     480             : 
     481             : static int
     482          10 : login_to_database(BCPPARAMDATA *pdata, DBPROCESS **pdbproc)
     483             : {
     484             :         LOGINREC *login;
     485             : 
     486             :         /* Initialize DB-Library. */
     487             : 
     488          10 :         if (dbinit() == FAIL)
     489             :                 return (FALSE);
     490             : 
     491             :         /*
     492             :          * Install the user-supplied error-handling and message-handling
     493             :          * routines. They are defined at the bottom of this source file.
     494             :          */
     495             : 
     496          10 :         dberrhandle(err_handler);
     497          10 :         dbmsghandle(msg_handler);
     498             : 
     499             :         /* If the interfaces file was specified explicitly, set it. */
     500          10 :         if (pdata->interfacesfile != NULL)
     501           0 :                 dbsetifile(pdata->interfacesfile);
     502             : 
     503             :         /*
     504             :          * Allocate and initialize the LOGINREC structure to be used
     505             :          * to open a connection to SQL Server.
     506             :          */
     507             : 
     508          10 :         login = dblogin();
     509          10 :         if (!login)
     510             :                 return FALSE;
     511             : 
     512          10 :         if (pdata->user)
     513          10 :                 DBSETLUSER(login, pdata->user);
     514          10 :         if (pdata->pass) {
     515          10 :                 DBSETLPWD(login, pdata->pass);
     516          10 :                 memset(pdata->pass, 0, strlen(pdata->pass));
     517             :         }
     518             : 
     519          10 :         DBSETLAPP(login, "FreeBCP");
     520          10 :         if (pdata->charset)
     521           0 :                 DBSETLCHARSET(login, pdata->charset);
     522             : 
     523          10 :         if (pdata->Aflag && pdata->packetsize > 0) {
     524           0 :                 DBSETLPACKET(login, pdata->packetsize);
     525             :         }
     526             : 
     527          10 :         if (pdata->dbname)
     528          10 :                 DBSETLDBNAME(login, pdata->dbname);
     529             : 
     530             :         /* Enable bulk copy for this connection. */
     531             : 
     532          10 :         BCP_SETL(login, TRUE);
     533             : 
     534             :         /*
     535             :          * Get a connection to the database.
     536             :          */
     537             : 
     538          10 :         if ((*pdbproc = dbopen(login, pdata->server)) == NULL) {
     539           0 :                 fprintf(stderr, "Can't connect to server \"%s\".\n", pdata->server);
     540           0 :                 dbloginfree(login);
     541           0 :                 return (FALSE);
     542             :         }
     543          10 :         dbloginfree(login);
     544          10 :         login = NULL;
     545             : 
     546          10 :         return (TRUE);
     547             : 
     548             : }
     549             : 
     550             : static RETCODE
     551          10 : format_column(BCPPARAMDATA *pdata, DBPROCESS *dbproc, BCPFORMAT file_format, int i, int is_last_column)
     552             : {
     553          10 :         int li_coltype = SYBCHAR;
     554          10 :         int host_prefixlen = 0;
     555          10 :         char *host_term = NULL;
     556          10 :         int host_termlen = -1;
     557             : 
     558          10 :         if (file_format == BCPFORMAT_NATIVE) {
     559           0 :                 li_coltype = dbcoltype(dbproc, i);
     560           0 :                 host_prefixlen = -1;
     561          10 :         } else if (is_last_column) {
     562          10 :                 host_term = pdata->rowterm;
     563          10 :                 host_termlen = pdata->rowtermlen;
     564             :         } else {
     565           0 :                 host_term = pdata->fieldterm;
     566           0 :                 host_termlen = pdata->fieldtermlen;
     567             :         }
     568             : 
     569          10 :         return bcp_colfmt(dbproc, i, li_coltype, host_prefixlen, -1, (const BYTE *) host_term, host_termlen, i);
     570             : }
     571             : 
     572             : static int
     573          10 : file_process(BCPPARAMDATA *pdata, DBPROCESS *dbproc, DBINT dir)
     574             : {
     575          10 :         DBINT li_rowsread = 0;
     576          10 :         DBINT li_rowscopied = 0;
     577             :         int i;
     578             :         int li_numcols;
     579             : 
     580          10 :         BCPFORMAT file_format = get_format(pdata);
     581             : 
     582             :         if (file_format == BCPFORMAT_NONE)
     583             :                 return FALSE;
     584             : 
     585          10 :         if (FAIL == bcp_init(dbproc, pdata->dbobject, pdata->hostfilename, pdata->errorfile, dir))
     586             :                 return FALSE;
     587             : 
     588          10 :         if (!set_bcp_hints(pdata, dbproc))
     589             :                 return FALSE;
     590             : 
     591          10 :         bcp_control(dbproc, BCPFIRST, pdata->firstrow);
     592          10 :         bcp_control(dbproc, BCPLAST, pdata->lastrow);
     593          10 :         bcp_control(dbproc, BCPMAXERRS, pdata->maxerrors);
     594          10 :         bcp_control(dbproc, BCPDRYRUN, pdata->dry_run);
     595             : 
     596          10 :         switch (file_format) {
     597           0 :         case BCPFORMAT_FORMATTED:
     598           0 :                 if (FAIL == bcp_readfmt(dbproc, pdata->formatfile))
     599             :                         return FALSE;
     600             :                 break;
     601             : 
     602             :                 /* The data file does not use TDS nullable types. It uses non-nullable
     603             :                  * representations, and a Length prefix if the target column was nullable.
     604             :                  * The length prefix typically takes value 0 or -1 to indicate a null.
     605             :                  * So, we need to check format of all columns.
     606             :                  */
     607          10 :         case BCPFORMAT_NATIVE:
     608             :         case BCPFORMAT_CHARACTER:
     609          10 :                 li_numcols = bcp_gethostcolcount(dbproc);
     610          20 :                 for (i = 1; i <= li_numcols; ++i) {
     611          10 :                         if (format_column(pdata, dbproc, file_format, i, i == li_numcols) == FAIL) {
     612           0 :                                 fprintf(stderr, "Error in bcp_colfmt col %d\n", i);
     613           0 :                                 return FALSE;
     614             :                         }
     615             :                 }
     616             :                 break;
     617             :         }
     618             : 
     619          10 :         if (file_format == BCPFORMAT_CHARACTER)
     620          10 :                 bcp_control(dbproc, BCPBATCH, pdata->batchsize);
     621             : 
     622             :         /* note: process_Eflag frees data needed by format_column() for NATIVE type,
     623             :          * so call this after the column loop. */
     624          10 :         if (!process_Eflag(pdata, dbproc))
     625             :                 return FALSE;
     626             : 
     627          10 :         printf("\nStarting copy%s...\n\n", pdata->dry_run ? " (dry run)" : "");
     628             : 
     629          10 :         if (FAIL == bcp_exec(dbproc, &li_rowscopied)) {
     630           0 :                 fprintf(stderr, "bcp copy %s failed\n", (dir == DB_IN) ? "in" : "out");
     631           0 :                 return FALSE;
     632             :         }
     633             : 
     634          10 :         if (li_rowsread > li_rowscopied)
     635           0 :                 printf("%d rows unable to be copied.\n", li_rowsread - li_rowscopied);
     636             : 
     637          10 :         printf("%d rows %scopied.\n", li_rowscopied, pdata->dry_run ? "would have been " : "");
     638             : 
     639          10 :         return TRUE;
     640             : }
     641             : 
     642             : static int
     643          10 : setoptions(DBPROCESS *dbproc, BCPPARAMDATA *params)
     644             : {
     645             :         RETCODE fOK;
     646             : 
     647          10 :         if (dbfcmd(dbproc, "set textsize %d ", params->textsize) == FAIL) {
     648           0 :                 fprintf(stderr, "setoptions() could not set textsize at %s:%d\n", __FILE__, __LINE__);
     649             :                 return FALSE;
     650             :         }
     651             : 
     652             :         /*
     653             :          * If the option is a filename, read the SQL text from the file.
     654             :          * Else pass the option verbatim to the server.
     655             :          */
     656          10 :         if (params->options) {
     657             :                 FILE *optFile;
     658             :                 char optBuf[256];
     659             : 
     660           0 :                 if ((optFile = fopen(params->options, "r")) == NULL) {
     661           0 :                         if (dbcmd(dbproc, params->options) == FAIL) {
     662           0 :                                 fprintf(stderr, "setoptions() failed preparing options at %s:%d\n", __FILE__, __LINE__);
     663           0 :                                 return FALSE;
     664             :                         }
     665             :                 } else {
     666           0 :                         while (fgets (optBuf, sizeof(optBuf), optFile) != NULL) {
     667           0 :                                 if (dbcmd(dbproc, optBuf) == FAIL) {
     668           0 :                                         fprintf(stderr, "setoptions() failed preparing options at %s:%d\n", __FILE__, __LINE__);
     669           0 :                                         fclose(optFile);
     670             :                                         return FALSE;
     671             :                                 }
     672             :                         }
     673           0 :                         if (!feof (optFile)) {
     674           0 :                                 perror("freebcp");
     675           0 :                                 fprintf(stderr, "error reading options file \"%s\" at %s:%d\n", params->options, __FILE__, __LINE__);
     676           0 :                                 fclose(optFile);
     677             :                                 return FALSE;
     678             :                         }
     679           0 :                         fclose(optFile);
     680             :                 }
     681             :         }
     682             : 
     683          10 :         if (dbsqlexec(dbproc) == FAIL) {
     684           0 :                 fprintf(stderr, "setoptions() failed sending options at %s:%d\n", __FILE__, __LINE__);
     685             :                 return FALSE;
     686             :         }
     687             : 
     688          20 :         while ((fOK = dbresults(dbproc)) == SUCCEED) {
     689          10 :                 while ((fOK = dbnextrow(dbproc)) == REG_ROW)
     690           0 :                         continue;
     691          10 :                 if (fOK == FAIL) {
     692           0 :                         fprintf(stderr, "setoptions() failed sending options at %s:%d\n", __FILE__, __LINE__);
     693             :                         return FALSE;
     694             :                 }
     695             :         }
     696          10 :         if (fOK == FAIL) {
     697           0 :                 fprintf(stderr, "setoptions() failed sending options at %s:%d\n", __FILE__, __LINE__);
     698             :                 return FALSE;
     699             :         }
     700             : 
     701             :         return TRUE;
     702             : }
     703             : 
     704             : static int
     705          10 : set_bcp_hints(BCPPARAMDATA *pdata, DBPROCESS *pdbproc)
     706             : {
     707             :         /* set hint if any */
     708          10 :         if (pdata->hint) {
     709           0 :                 if (bcp_options(pdbproc, BCPHINTS, (BYTE *) pdata->hint, strlen(pdata->hint)) != SUCCEED) {
     710           0 :                         fprintf(stderr, "db-lib: Unable to set hint \"%s\"\n", pdata->hint);
     711             :                         return FALSE;
     712             :                 }
     713             :         }
     714             :         return TRUE;
     715             : }
     716             : 
     717             : static void
     718           0 : pusage(void)
     719             : {
     720           0 :         fprintf(stderr, "usage:  freebcp [[database_name.]owner.]table_name|query {in | out | queryout } datafile\n");
     721           0 :         fprintf(stderr, "        [-m maxerrors] [-f formatfile] [-e errfile]\n");
     722           0 :         fprintf(stderr, "        [-F firstrow] [-L lastrow] [-b batchsize]\n");
     723           0 :         fprintf(stderr, "        [-n] [-c] [-t field_terminator] [-r row_terminator]\n");
     724           0 :         fprintf(stderr, "        [-U username] [-P password] [-I interfaces_file] [-S server] [-D database]\n");
     725           0 :         fprintf(stderr, "        [-v] [-d] [-h \"hint [,...]\" [-O \"set connection_option on|off, ...]\"\n");
     726           0 :         fprintf(stderr, "        [-A packet size] [-T text or image size] [-E]\n");
     727           0 :         fprintf(stderr, "        [-i input_file] [-o output_file] [-k] [-j]\n");
     728           0 :         fprintf(stderr, "        \n");
     729           0 :         fprintf(stderr, "example: freebcp testdb.dbo.inserttest in inserttest.txt -S mssql -U guest -P password -c\n");
     730           0 : }
     731             : 
     732             : static int
     733          20 : err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr TDS_UNUSED, char *dberrstr, char *oserrstr TDS_UNUSED)
     734             : {
     735             :         static int sent = 0;
     736             : 
     737          20 :         if (dberr == SYBEBBCI) { /* Batch successfully bulk copied to the server */
     738           0 :                 int batch = bcp_getbatchsize(dbproc);
     739           0 :                 printf("%d rows sent to SQL Server.\n", sent += batch);
     740           0 :                 return INT_CANCEL;
     741             :         }
     742             : 
     743          20 :         if (dberr) {
     744          20 :                 fprintf(stderr, "Msg %d, Level %d\n", dberr, severity);
     745          20 :                 fprintf(stderr, "%s\n\n", dberrstr);
     746             :         } else {
     747           0 :                 fprintf(stderr, "DB-LIBRARY error:\n\t");
     748           0 :                 fprintf(stderr, "%s\n", dberrstr);
     749             :         }
     750             : 
     751             :         return INT_CANCEL;
     752             : }
     753             : 
     754             : static int
     755          20 : msg_handler(DBPROCESS *dbproc TDS_UNUSED, DBINT msgno, int msgstate, int severity,
     756             :             char *msgtext, char *srvname, char *procname, int line)
     757             : {
     758             :         /*
     759             :          * If it's a database change message, we'll ignore it.
     760             :          * Also ignore language change message.
     761             :          */
     762          20 :         if (msgno == 5701 || msgno == 5703)
     763             :                 return (0);
     764             : 
     765           0 :         fprintf(stderr, "Msg %ld, Level %d, State %d\n", (long) msgno, severity, msgstate);
     766             : 
     767           0 :         if (strlen(srvname) > 0)
     768           0 :                 fprintf(stderr, "Server '%s', ", srvname);
     769           0 :         if (strlen(procname) > 0)
     770           0 :                 fprintf(stderr, "Procedure '%s', ", procname);
     771           0 :         if (line > 0)
     772           0 :                 fprintf(stderr, "Line %d", line);
     773             : 
     774           0 :         fprintf(stderr, "\n\t%s\n", msgtext);
     775             : 
     776           0 :         return (0);
     777             : }
     778             : 
     779             : static void
     780          10 : bcpparamdata_free(BCPPARAMDATA *params)
     781             : {
     782          10 :         free(params->dbobject);
     783          10 :         free(params->hostfilename);
     784          10 :         free(params->formatfile);
     785          10 :         free(params->errorfile);
     786          10 :         free(params->interfacesfile);
     787          10 :         free(params->fieldterm);
     788          10 :         free(params->rowterm);
     789          10 :         free(params->user);
     790          10 :         free(params->pass);
     791          10 :         free(params->server);
     792          10 :         free(params->dbname);
     793          10 :         free(params->hint);
     794          10 :         free(params->options);
     795          10 :         free(params->charset);
     796          10 :         free(params->inputfile);
     797          10 :         free(params->outputfile);
     798          10 : }

Generated by: LCOV version 1.13