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