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:k")) != -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 '?':
366 : default:
367 0 : pusage();
368 0 : return (FALSE);
369 : }
370 : }
371 :
372 : /*
373 : * Check for required/disallowed option combinations
374 : * If no username is provided, rely on domain login.
375 : */
376 :
377 : /* Server */
378 10 : if (!pdata->Sflag) {
379 0 : if ((pdata->server = getenv("DSQUERY")) != NULL) {
380 0 : pdata->server = xstrdup(pdata->server); /* can be freed */
381 0 : pdata->Sflag = true;
382 : } else {
383 0 : fprintf(stderr, "-S must be supplied.\n");
384 0 : return (FALSE);
385 : }
386 : }
387 :
388 : /* Only one of these can be specified */
389 10 : if (!!pdata->cflag + !!pdata->nflag + !!pdata->fflag != 1) {
390 0 : fprintf(stderr, "Exactly one of options -c, -n, -f must be supplied.\n");
391 0 : return (FALSE);
392 : }
393 :
394 : /* Character mode file: fill in default values */
395 10 : if (pdata->cflag) {
396 :
397 10 : if (!pdata->tflag || !pdata->fieldterm) { /* field terminator not specified */
398 10 : pdata->fieldterm = xstrdup("\t");
399 10 : pdata->fieldtermlen = 1;
400 : }
401 10 : if (!pdata->rflag || !pdata->rowterm) { /* row terminator not specified */
402 : #ifdef _WIN32
403 : pdata->rowterm = xstrdup("\r\n");
404 : pdata->rowtermlen = 2;
405 : #else
406 10 : pdata->rowterm = xstrdup("\n");
407 10 : pdata->rowtermlen = 1;
408 : #endif
409 : }
410 : }
411 :
412 : /* -k will be implemented on MSSQL by -hKEEP_NULLS */
413 10 : if (pdata->ignoreDefaults) {
414 0 : if (!pdata->hint)
415 0 : pdata->hint = xstrdup("KEEP_NULLS");
416 0 : else if (strstr(pdata->hint, "KEEP_NULLS") == NULL) {
417 : /* Append to existing hints if not already present */
418 : char *hints;
419 0 : int ret = asprintf(&hints, "%s,KEEP_NULLS", pdata->hint);
420 :
421 0 : if (ret < 0) {
422 0 : fprintf(stderr, "Failed to apply -k flag to hints");
423 0 : return FALSE;
424 : }
425 0 : free(pdata->hint);
426 0 : pdata->hint = hints;
427 : }
428 : }
429 :
430 : /*
431 : * Override stdin and/or stdout if requested.
432 : */
433 :
434 : /* FIXME -- Since we don't implement prompting for field data types when neither -c nor -n
435 : * is specified, redirecting stdin doesn't do much yet.
436 : */
437 10 : if (pdata->inputfile) {
438 0 : if (freopen(pdata->inputfile, "rb", stdin) == NULL) {
439 0 : fprintf(stderr, "%s: unable to open %s: %s\n", "freebcp", pdata->inputfile, strerror(errno));
440 0 : exit(EXIT_FAILURE);
441 : }
442 : }
443 :
444 10 : if (pdata->outputfile) {
445 0 : if (freopen(pdata->outputfile, "wb", stdout) == NULL) {
446 0 : fprintf(stderr, "%s: unable to open %s: %s\n", "freebcp", pdata->outputfile, strerror(errno));
447 0 : exit(EXIT_FAILURE);
448 : }
449 : }
450 :
451 : return (TRUE);
452 :
453 : }
454 :
455 : static int
456 10 : process_Eflag(BCPPARAMDATA *pdata, DBPROCESS *dbproc)
457 : {
458 10 : if (pdata->Eflag) {
459 :
460 0 : bcp_control(dbproc, BCPKEEPIDENTITY, 1);
461 :
462 0 : if (dbfcmd(dbproc, "set identity_insert %s on", pdata->dbobject) == FAIL) {
463 0 : fprintf(stderr, "dbfcmd failed\n");
464 : return FALSE;
465 : }
466 :
467 0 : if (dbsqlexec(dbproc) == FAIL) {
468 0 : fprintf(stderr, "dbsqlexec failed\n");
469 : return FALSE;
470 : }
471 :
472 0 : while (NO_MORE_RESULTS != dbresults(dbproc))
473 0 : continue;
474 : }
475 : return TRUE;
476 : }
477 :
478 : static int
479 10 : login_to_database(BCPPARAMDATA *pdata, DBPROCESS **pdbproc)
480 : {
481 : LOGINREC *login;
482 :
483 : /* Initialize DB-Library. */
484 :
485 10 : if (dbinit() == FAIL)
486 : return (FALSE);
487 :
488 : /*
489 : * Install the user-supplied error-handling and message-handling
490 : * routines. They are defined at the bottom of this source file.
491 : */
492 :
493 10 : dberrhandle(err_handler);
494 10 : dbmsghandle(msg_handler);
495 :
496 : /* If the interfaces file was specified explicitly, set it. */
497 10 : if (pdata->interfacesfile != NULL)
498 0 : dbsetifile(pdata->interfacesfile);
499 :
500 : /*
501 : * Allocate and initialize the LOGINREC structure to be used
502 : * to open a connection to SQL Server.
503 : */
504 :
505 10 : login = dblogin();
506 10 : if (!login)
507 : return FALSE;
508 :
509 10 : if (pdata->user)
510 10 : DBSETLUSER(login, pdata->user);
511 10 : if (pdata->pass) {
512 10 : DBSETLPWD(login, pdata->pass);
513 10 : memset(pdata->pass, 0, strlen(pdata->pass));
514 : }
515 :
516 10 : DBSETLAPP(login, "FreeBCP");
517 10 : if (pdata->charset)
518 0 : DBSETLCHARSET(login, pdata->charset);
519 :
520 10 : if (pdata->Aflag && pdata->packetsize > 0) {
521 0 : DBSETLPACKET(login, pdata->packetsize);
522 : }
523 :
524 10 : if (pdata->dbname)
525 10 : DBSETLDBNAME(login, pdata->dbname);
526 :
527 : /* Enable bulk copy for this connection. */
528 :
529 10 : BCP_SETL(login, TRUE);
530 :
531 : /*
532 : * Get a connection to the database.
533 : */
534 :
535 10 : if ((*pdbproc = dbopen(login, pdata->server)) == NULL) {
536 0 : fprintf(stderr, "Can't connect to server \"%s\".\n", pdata->server);
537 0 : dbloginfree(login);
538 0 : return (FALSE);
539 : }
540 10 : dbloginfree(login);
541 10 : login = NULL;
542 :
543 10 : return (TRUE);
544 :
545 : }
546 :
547 : static RETCODE
548 10 : format_column(BCPPARAMDATA *pdata, DBPROCESS *dbproc, BCPFORMAT file_format, int i, int is_last_column)
549 : {
550 10 : int li_coltype = SYBCHAR;
551 10 : int host_prefixlen = 0;
552 10 : char *host_term = NULL;
553 10 : int host_termlen = -1;
554 :
555 10 : if (file_format == BCPFORMAT_NATIVE) {
556 0 : li_coltype = dbcoltype(dbproc, i);
557 0 : host_prefixlen = -1;
558 10 : } else if (is_last_column) {
559 10 : host_term = pdata->rowterm;
560 10 : host_termlen = pdata->rowtermlen;
561 : } else {
562 0 : host_term = pdata->fieldterm;
563 0 : host_termlen = pdata->fieldtermlen;
564 : }
565 :
566 10 : return bcp_colfmt(dbproc, i, li_coltype, host_prefixlen, -1, (const BYTE *) host_term, host_termlen, i);
567 : }
568 :
569 : static int
570 10 : file_process(BCPPARAMDATA *pdata, DBPROCESS *dbproc, DBINT dir)
571 : {
572 10 : DBINT li_rowsread = 0;
573 10 : DBINT li_rowscopied = 0;
574 : int i;
575 : int li_numcols;
576 :
577 10 : BCPFORMAT file_format = get_format(pdata);
578 :
579 : if (file_format == BCPFORMAT_NONE)
580 : return FALSE;
581 :
582 10 : if (FAIL == bcp_init(dbproc, pdata->dbobject, pdata->hostfilename, pdata->errorfile, dir))
583 : return FALSE;
584 :
585 10 : if (!set_bcp_hints(pdata, dbproc))
586 : return FALSE;
587 :
588 10 : bcp_control(dbproc, BCPFIRST, pdata->firstrow);
589 10 : bcp_control(dbproc, BCPLAST, pdata->lastrow);
590 10 : bcp_control(dbproc, BCPMAXERRS, pdata->maxerrors);
591 :
592 10 : switch (file_format) {
593 0 : case BCPFORMAT_FORMATTED:
594 0 : if (FAIL == bcp_readfmt(dbproc, pdata->formatfile))
595 : return FALSE;
596 : break;
597 :
598 : /* The data file does not use TDS nullable types. It uses non-nullable
599 : * representations, and a Length prefix if the target column was nullable.
600 : * The length prefix typically takes value 0 or -1 to indicate a null.
601 : * So, we need to check format of all columns.
602 : */
603 10 : case BCPFORMAT_NATIVE:
604 : case BCPFORMAT_CHARACTER:
605 10 : li_numcols = bcp_gethostcolcount(dbproc);
606 20 : for (i = 1; i <= li_numcols; ++i) {
607 10 : if (format_column(pdata, dbproc, file_format, i, i == li_numcols) == FAIL) {
608 0 : fprintf(stderr, "Error in bcp_colfmt col %d\n", i);
609 0 : return FALSE;
610 : }
611 : }
612 : break;
613 : }
614 :
615 10 : if (file_format == BCPFORMAT_CHARACTER)
616 10 : bcp_control(dbproc, BCPBATCH, pdata->batchsize);
617 :
618 : /* note: process_Eflag frees data needed by format_column() for NATIVE type,
619 : * so call this after the column loop. */
620 10 : if (!process_Eflag(pdata, dbproc))
621 : return FALSE;
622 :
623 10 : printf("\nStarting copy...\n\n");
624 :
625 10 : if (FAIL == bcp_exec(dbproc, &li_rowscopied)) {
626 0 : fprintf(stderr, "bcp copy %s failed\n", (dir == DB_IN) ? "in" : "out");
627 0 : return FALSE;
628 : }
629 :
630 10 : if (li_rowsread > li_rowscopied)
631 0 : printf("%d rows unable to be copied.\n", li_rowsread - li_rowscopied);
632 :
633 10 : printf("%d rows copied.\n", li_rowscopied);
634 :
635 10 : return TRUE;
636 : }
637 :
638 : static int
639 10 : setoptions(DBPROCESS *dbproc, BCPPARAMDATA *params)
640 : {
641 : RETCODE fOK;
642 :
643 10 : if (dbfcmd(dbproc, "set textsize %d ", params->textsize) == FAIL) {
644 0 : fprintf(stderr, "setoptions() could not set textsize at %s:%d\n", __FILE__, __LINE__);
645 : return FALSE;
646 : }
647 :
648 : /*
649 : * If the option is a filename, read the SQL text from the file.
650 : * Else pass the option verbatim to the server.
651 : */
652 10 : if (params->options) {
653 : FILE *optFile;
654 : char optBuf[256];
655 :
656 0 : if ((optFile = fopen(params->options, "r")) == NULL) {
657 0 : if (dbcmd(dbproc, params->options) == FAIL) {
658 0 : fprintf(stderr, "setoptions() failed preparing options at %s:%d\n", __FILE__, __LINE__);
659 0 : return FALSE;
660 : }
661 : } else {
662 0 : while (fgets (optBuf, sizeof(optBuf), optFile) != NULL) {
663 0 : if (dbcmd(dbproc, optBuf) == FAIL) {
664 0 : fprintf(stderr, "setoptions() failed preparing options at %s:%d\n", __FILE__, __LINE__);
665 0 : fclose(optFile);
666 : return FALSE;
667 : }
668 : }
669 0 : if (!feof (optFile)) {
670 0 : perror("freebcp");
671 0 : fprintf(stderr, "error reading options file \"%s\" at %s:%d\n", params->options, __FILE__, __LINE__);
672 0 : fclose(optFile);
673 : return FALSE;
674 : }
675 0 : fclose(optFile);
676 : }
677 : }
678 :
679 10 : if (dbsqlexec(dbproc) == FAIL) {
680 0 : fprintf(stderr, "setoptions() failed sending options at %s:%d\n", __FILE__, __LINE__);
681 : return FALSE;
682 : }
683 :
684 20 : while ((fOK = dbresults(dbproc)) == SUCCEED) {
685 10 : while ((fOK = dbnextrow(dbproc)) == REG_ROW)
686 0 : continue;
687 10 : if (fOK == FAIL) {
688 0 : fprintf(stderr, "setoptions() failed sending options at %s:%d\n", __FILE__, __LINE__);
689 : return FALSE;
690 : }
691 : }
692 10 : if (fOK == FAIL) {
693 0 : fprintf(stderr, "setoptions() failed sending options at %s:%d\n", __FILE__, __LINE__);
694 : return FALSE;
695 : }
696 :
697 : return TRUE;
698 : }
699 :
700 : static int
701 10 : set_bcp_hints(BCPPARAMDATA *pdata, DBPROCESS *pdbproc)
702 : {
703 : /* set hint if any */
704 10 : if (pdata->hint) {
705 0 : if (bcp_options(pdbproc, BCPHINTS, (BYTE *) pdata->hint, strlen(pdata->hint)) != SUCCEED) {
706 0 : fprintf(stderr, "db-lib: Unable to set hint \"%s\"\n", pdata->hint);
707 : return FALSE;
708 : }
709 : }
710 : return TRUE;
711 : }
712 :
713 : static void
714 0 : pusage(void)
715 : {
716 0 : fprintf(stderr, "usage: freebcp [[database_name.]owner.]table_name|query {in | out | queryout } datafile\n");
717 0 : fprintf(stderr, " [-m maxerrors] [-f formatfile] [-e errfile]\n");
718 0 : fprintf(stderr, " [-F firstrow] [-L lastrow] [-b batchsize]\n");
719 0 : fprintf(stderr, " [-n] [-c] [-t field_terminator] [-r row_terminator]\n");
720 0 : fprintf(stderr, " [-U username] [-P password] [-I interfaces_file] [-S server] [-D database]\n");
721 0 : fprintf(stderr, " [-v] [-d] [-h \"hint [,...]\" [-O \"set connection_option on|off, ...]\"\n");
722 0 : fprintf(stderr, " [-A packet size] [-T text or image size] [-E]\n");
723 0 : fprintf(stderr, " [-i input_file] [-o output_file] [-k]\n");
724 0 : fprintf(stderr, " \n");
725 0 : fprintf(stderr, "example: freebcp testdb.dbo.inserttest in inserttest.txt -S mssql -U guest -P password -c\n");
726 0 : }
727 :
728 : static int
729 20 : err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr TDS_UNUSED, char *dberrstr, char *oserrstr TDS_UNUSED)
730 : {
731 : static int sent = 0;
732 :
733 20 : if (dberr == SYBEBBCI) { /* Batch successfully bulk copied to the server */
734 0 : int batch = bcp_getbatchsize(dbproc);
735 0 : printf("%d rows sent to SQL Server.\n", sent += batch);
736 0 : return INT_CANCEL;
737 : }
738 :
739 20 : if (dberr) {
740 20 : fprintf(stderr, "Msg %d, Level %d\n", dberr, severity);
741 20 : fprintf(stderr, "%s\n\n", dberrstr);
742 : } else {
743 0 : fprintf(stderr, "DB-LIBRARY error:\n\t");
744 0 : fprintf(stderr, "%s\n", dberrstr);
745 : }
746 :
747 : return INT_CANCEL;
748 : }
749 :
750 : static int
751 20 : msg_handler(DBPROCESS *dbproc TDS_UNUSED, DBINT msgno, int msgstate, int severity,
752 : char *msgtext, char *srvname, char *procname, int line)
753 : {
754 : /*
755 : * If it's a database change message, we'll ignore it.
756 : * Also ignore language change message.
757 : */
758 20 : if (msgno == 5701 || msgno == 5703)
759 : return (0);
760 :
761 0 : fprintf(stderr, "Msg %ld, Level %d, State %d\n", (long) msgno, severity, msgstate);
762 :
763 0 : if (strlen(srvname) > 0)
764 0 : fprintf(stderr, "Server '%s', ", srvname);
765 0 : if (strlen(procname) > 0)
766 0 : fprintf(stderr, "Procedure '%s', ", procname);
767 0 : if (line > 0)
768 0 : fprintf(stderr, "Line %d", line);
769 :
770 0 : fprintf(stderr, "\n\t%s\n", msgtext);
771 :
772 0 : return (0);
773 : }
774 :
775 : static void
776 10 : bcpparamdata_free(BCPPARAMDATA *params)
777 : {
778 10 : free(params->dbobject);
779 10 : free(params->hostfilename);
780 10 : free(params->formatfile);
781 10 : free(params->errorfile);
782 10 : free(params->interfacesfile);
783 10 : free(params->fieldterm);
784 10 : free(params->rowterm);
785 10 : free(params->user);
786 10 : free(params->pass);
787 10 : free(params->server);
788 10 : free(params->dbname);
789 10 : free(params->hint);
790 10 : free(params->options);
791 10 : free(params->charset);
792 10 : free(params->inputfile);
793 10 : free(params->outputfile);
794 10 : }
|