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(¶ms, '\0', sizeof(params));
107 :
108 10 : params.textsize = 4096; /* our default text size is 4K */
109 :
110 10 : if (process_parameters(argc, argv, ¶ms) == 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(¶ms, &dbproc) == FALSE) {
119 0 : exit(EXIT_FAILURE);
120 : }
121 :
122 10 : if (!setoptions(dbproc, ¶ms))
123 : return FALSE;
124 :
125 10 : ok = file_process(¶ms, dbproc, params.direction);
126 :
127 10 : dbclose(dbproc);
128 10 : dbexit();
129 10 : bcpparamdata_free(¶ms);
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 : }
|