1 /*
2 * cmd_bcp.c - User command to bcp result set to another server.
3 *
4 * Copyright (C) 1995, 1996 by Scott C. Gray
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, write to the Free Software
18 * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * You may contact the author :
21 * e-mail: gray@voicenet.com
22 * grays@xtend-tech.com
23 * gray@xenotropic.com
24 */
25 #include <stdio.h>
26 #include <ctpublic.h>
27 #include <ctype.h>
28 #include <bkpublic.h>
29 #include "sqsh_config.h"
30 #include "sqsh_global.h"
31 #include "sqsh_expand.h"
32 #include "sqsh_error.h"
33 #include "sqsh_varbuf.h"
34 #include "sqsh_getopt.h"
35 #include "sqsh_env.h"
36 #include "sqsh_cmd.h"
37 #include "sqsh_sig.h"
38 #include "cmd.h"
39
40
41 /*-- Current Version --*/
42 #if !defined(lint) && !defined(__LINT__)
43 static char RCS_Id[] = "$Id: cmd_bcp.c,v 1.21 2014/04/04 08:22:38 mwesdorp Exp $";
44 USE(RCS_Id)
45 #endif /* !defined(lint) */
46
47 /*
48 * The following macro is used to convert a start time and end
49 * time into total elapsed number of seconds, to the decimal
50 * place.
51 */
52 #define ELAPSED_SEC(tv_start,tv_end) \
53 (((double)(tv_end.tv_sec - tv_start.tv_sec)) + \
54 ((double)(tv_end.tv_usec - tv_start.tv_usec)) / ((double)1000000.0))
55
56 /*
57 * sg_interrupted: This variable is set by the bcp_signal() signal
58 * handler and is to be polled periodically to determine if
59 * a signal has been recieved.
60 */
61 static int sg_interrupted = False;
62
63 /*
64 * sg_error: This variable is set by the callback functions and is
65 * used when the init command returns an error.
66 */
67 static int sg_error = False;
68
69 /*
70 * sg_bcp_connection: This variable is used by the signal handler
71 * to determine which connection needs to be canceled.
72 */
73 static CS_CONNECTION *sg_bcp_connection = NULL;
74
75 /*
76 * The following are used during debugging to convert an internal
77 * sybase id (such as a bind-type and a data type) to a readable
78 * string.
79 */
80 #if defined(DEBUG)
81
82 /*
83 * Id vs. name structure.
84 */
85 typedef struct idname_st {
86 int id;
87 char *name;
88 } idname_t;
89
90 #endif /* DEBUG */
91
92 /*
93 * bcp_col_t: This data structure represents a single column of data
94 * as it returns from the server. Note that all data is
95 * fetched and sent in its native data type.
96 */
97 typedef struct _bcp_col_t {
98 CS_INT c_colid; /* Column number */
99 CS_DATAFMT c_format; /* Format for column */
100 CS_INT c_len; /* Length of current row */
101 CS_INT c_prevlen; /* Length of previous row */
102 CS_SMALLINT c_nullind; /* Null indicator for current row */
103 CS_SMALLINT c_prevnullind; /* Null indicator for previous row */
104 CS_VOID *c_data; /* Data space for fetch and bind */
105 } bcp_col_t;
106
107 /*
108 * bcp_data_t: Represents an entire row of data.
109 */
110 typedef struct _bcp_data_t {
111 CS_INT d_type; /* Result type */
112 CS_INT d_ncols; /* Number of columns to fetch */
113 CS_BOOL d_bound; /* Have we bound */
114 bcp_col_t *d_cols; /* Array of columns */
115 } bcp_data_t;
116
117 /*-- Prototypes --*/
118 static void bcp_signal _ANSI_ARGS(( int, void* ));
119 static bcp_data_t* bcp_data_bind _ANSI_ARGS(( CS_COMMAND*, CS_INT ));
120 static CS_INT bcp_data_xfer _ANSI_ARGS(( bcp_data_t*, CS_COMMAND*, CS_BLKDESC* ));
121 static void bcp_data_destroy _ANSI_ARGS(( bcp_data_t* ));
122 static CS_RETCODE bcp_server_cb
123 _ANSI_ARGS(( CS_CONTEXT*, CS_CONNECTION*, CS_SERVERMSG* ))
124 #if defined(__CYGWIN__)
125 __attribute__ ((stdcall))
126 #endif /* __CYGWIN__ */
127 ;
128
129 static CS_RETCODE bcp_client_cb
130 _ANSI_ARGS(( CS_CONTEXT*, CS_CONNECTION*, CS_CLIENTMSG* ))
131 #if defined(__CYGWIN__)
132 __attribute__ ((stdcall))
133 #endif /* __CYGWIN__ */
134 ;
135
136 #if defined(CS_SSLVALIDATE_CB)
137 static CS_RETCODE validate_srvname_cb
138 _ANSI_ARGS(( CS_VOID*, CS_SSLCERT*, CS_INT, CS_INT ))
139 #if defined(__CYGWIN__)
140 __attribute__ ((stdcall))
141 #endif /* __CYGWIN__ */
142 ;
143 #endif
144
cmd_bcp(argc,argv)145 int cmd_bcp( argc, argv )
146 int argc ;
147 char *argv[] ;
148 {
149 char *password; /* Current password */
150 char *username; /* Value of $username variable */
151 char *server; /* Value of $server variable */
152 char *expand; /* Value of $expand variable */
153 char *packet_size; /* Value of $packet_size variable */
154 char *charset; /* Value of $charset */
155 char *language; /* Value of $language */
156 char *database; /* Value of $database */
157 char *encryption; /* Value of $encryption */
158 char *hostname; /* Value of $hostname */
159 extern int sqsh_optind; /* Current option index in sqsh_getopt */
160 extern char* sqsh_optarg; /* Value of option */
161 int opt; /* Current option */
162 char *bcp_table; /* Table to bcp into */
163 char *bcp_partition; /* Partition name to bcp into */
164 int bcp_slicenum; /* Partition number to bcp into */
165 char *cmd_sql; /* SQL command to send to server */
166 int rows_in_batch; /* Rows processed in batch */
167 int total_rows; /* Total rows processing */
168 struct timeval tv_start; /* Time we started processing */
169 struct timeval tv_end; /* Time we finished processing */
170 double secs; /* Seconds spend transferring data */
171 int nerrors; /* Number of errors encountered */
172 CS_INT result_type; /* Result type coming from server */
173 CS_INT return_code; /* Return code from ct_results() */
174 CS_INT nrows; /* Rows transferred */
175 CS_BOOL bcp_on = CS_TRUE; /* Flag to turn on bulk login */
176 CS_INT i;
177 CS_INT con_status;
178 char *cp;
179
180 /*
181 * The following variables need to be initialized to check if
182 * they need cleaning up before we exit this procedure.
183 */
184 CS_COMMAND *bcp_cmd = NULL; /* Command sent to server */
185 CS_CONNECTION *bcp_con = NULL; /* Connection to use for transfer */
186 CS_BLKDESC *bcp_desc = NULL; /* Block descriptor */
187 CS_LOCALE *bcp_locale = NULL; /* Locale for bcp connection */
188 varbuf_t *exp_buf = NULL; /* Variable expansion buffer */
189 bcp_data_t *bcp_dat = NULL; /* Bind data */
190 CS_INT blk_ver = -1; /* BLK_VERSION_xxx value to use */
191
192
193 #if defined(CTLIB_SIGPOLL_BUG) && defined(F_SETOWN)
194 int ctlib_fd;
195 #endif
196
197 /*
198 * The following variables define default values that
199 * may be overriden by command line arguments.
200 */
201 int maxerrors = 10; /* Errors before abort */
202 int batchsize = -1; /* Copy all rows in one batch */
203 int have_error = False;
204 CS_BOOL have_identity = CS_FALSE;
205 #if defined (CS_NOCHARSETCNV_REQD) && defined (BLK_CONV)
206 CS_BOOL char_convert = CS_FALSE; /* Used with -T option (transit) */
207 CS_BOOL transit = CS_FALSE; /* Disable client character conversion */
208 #endif
209
210 /*
211 * sqsh-2.1.9 - Feature BCP execute an initialization command
212 */
213 char *init_cmd = NULL; /* BCP init command option */
214 CS_COMMAND *bcp_cmd_init = NULL; /* Command sent to server */
215 CS_RETCODE retcode; /* return code */
216
217 /*
218 * Retrieve value of variables used to configure the connection.
219 * These values may be overriden by command line parameters.
220 */
221 password = g_password;
222 env_get( g_env, "username", &username );
223 env_get( g_env, "DSQUERY", &server );
224 env_get( g_env, "expand", &expand );
225 env_get( g_env, "database", &database );
226 env_get( g_env, "charset", &charset );
227 env_get( g_env, "language", &language );
228 env_get( g_env, "encryption", &encryption );
229 env_get( g_env, "hostname", &hostname );
230 env_get( g_env, "packet_size", &packet_size );
231
232 while ((opt = sqsh_getopt( argc, argv, "A:b:I:i:J:m:NP;S:TU:Xz:" )) != EOF)
233 {
234 switch (opt)
235 {
236 case 'A':
237 packet_size = sqsh_optarg;
238 break;
239
240 case 'b':
241 if ((batchsize = atoi(sqsh_optarg)) <= 0)
242 {
243 fprintf(stderr, "\\bcp: -b: Invalid value '%s'\n", sqsh_optarg);
244 return CMD_FAIL;
245 }
246 break;
247
248 case 'I' :
249 if (env_set( g_env, "interfaces", sqsh_optarg ) == False)
250 {
251 fprintf( stderr, "\\bcp: -I: %s\n", sqsh_get_errstr() );
252 return CMD_FAIL;
253 }
254 break;
255
256 case 'i' :
257 init_cmd = sqsh_optarg;
258 break;
259
260 case 'J' :
261 charset = sqsh_optarg;
262 break;
263
264 case 'm':
265 if ((maxerrors = atoi(sqsh_optarg)) <= 0)
266 {
267 fprintf(stderr, "\\bcp: -m: Invalid value '%s'\n", sqsh_optarg);
268 return CMD_FAIL;
269 }
270 break;
271
272 case 'N':
273 have_identity = CS_TRUE;
274 break;
275
276 case 'P' :
277 password = sqsh_optarg;
278 break;
279
280 case 'S' :
281 server = sqsh_optarg;
282 break;
283
284 case 'T' :
285 #if defined (CS_NOCHARSETCNV_REQD) && defined (BLK_CONV)
286 transit = CS_TRUE;
287 #else
288 fprintf(stderr, "\\bcp: -T: Transit option is not supported by bulkcopy library\n");
289 fprintf(stderr, "\\bcp: -T: Parameter will be ignored\n");
290 #endif
291 break;
292
293 case 'U' :
294 username = sqsh_optarg;
295 break;
296
297 case 'X' :
298 encryption = "1";
299 break;
300
301 case 'z' :
302 language = sqsh_optarg;
303 break;
304
305 default:
306 fprintf(stderr,"\\bcp: %c: %s\n", opt, sqsh_get_errstr() );
307 have_error = True;
308 }
309 }
310
311 /*
312 * If there isn't a table name left on the command line, or an
313 * invalid argument was supplied, then print out usage
314 * information.
315 */
316 if ((argc - sqsh_optind) != 1 || have_error)
317 {
318 fprintf(stderr,
319 "Use: \\bcp [-A packsetsize] [-b batchsize] [-I interfaces] [-i initcmd]\n"
320 " [-J charset] [-m maxerrors] [-N] [-P password]\n"
321 " [-S server] [-T] [-U username] [-X] [-z language] table_name\n");
322 return CMD_FAIL;
323 }
324
325 /*
326 * Keep around a handy pointer.
327 */
328 bcp_table = argv[sqsh_optind];
329
330 /*
331 * sqsh-2.2.0 - Feature enable BCP_IN into a specific partition of a partitioned table
332 */
333 if ((bcp_partition = strchr(bcp_table, (int) ':')) != NULL)
334 {
335 *bcp_partition++ = '\0';
336 }
337
338 /*
339 * Now, install our signal handlers. At this point, all code should
340 * perform a goto {return_fail or return_interrupt} to return an error
341 * condition. This is important in order to clean up the signal
342 * handlers and various other data structures created.
343 */
344 sg_interrupted = False;
345 sg_error = False;
346 sg_bcp_connection = NULL;
347
348 sig_save();
349 sig_install( SIGINT, bcp_signal, (void*)NULL, 0 );
350 sig_install( SIGPIPE, bcp_signal, (void*)NULL, 0 );
351
352 /*
353 * Before we actually attempt to establish a connection to the
354 * remote database (that we are bcp'ing too), lets launch our
355 * query and see if it is valid.
356 */
357 if (expand == NULL || *expand != '0')
358 {
359 /*
360 * Temporarily create a buffer in which to store the expanded
361 * SQL buffer.
362 */
363 if ((exp_buf = varbuf_create(512)) == NULL)
364 {
365 fprintf(stderr, "\\bcp: varbuf_create: %s\n", sqsh_get_errstr());
366 goto return_fail;
367 }
368
369 if (sqsh_expand( varbuf_getstr( g_sqlbuf ), exp_buf,
370 EXP_STRIPESC|EXP_COMMENT|EXP_COLUMNS ) == False)
371 {
372 fprintf(stderr, "\\bcp: sqsh_expand: %s\n", sqsh_get_errstr());
373 goto return_fail;
374 }
375
376 cmd_sql = varbuf_getstr( exp_buf );
377
378 }
379 else
380 {
381 cmd_sql = varbuf_getstr( g_sqlbuf );
382 }
383
384 /*-- Initialize timing --*/
385 gettimeofday( &tv_start, NULL );
386 total_rows = 0;
387
388 /*-- Allocate a new command structure --*/
389 if (ct_cmd_alloc( g_connection, &bcp_cmd ) != CS_SUCCEED)
390 {
391 fprintf( stderr, "\\bcp: Unable to allocate new command\n" );
392 goto return_fail;
393 }
394
395 /*-- Find the appropriate BLK_VERSION_xxx value --*/
396 /*-- sqsh-2.1.7 - Make it compile with freetds-0.82 --*/
397 /*-- sqsh-2.1.9 - Added version BLK_VERSION_157 --*/
398 /*-- sqsh-2.5.16 - Added version BLK_VERSION_160 --*/
399 #if defined(CS_VERSION_160)
400 if(blk_ver == -1 && g_cs_ver == CS_VERSION_160) {
401 #if defined(BLK_VERSION_160)
402 blk_ver = BLK_VERSION_160;
403 #else
404 blk_ver = BLK_VERSION_110;
405 #endif
406 }
407 #endif
408 #if defined(CS_VERSION_157)
409 if(blk_ver == -1 && g_cs_ver == CS_VERSION_157) {
410 #if defined(BLK_VERSION_157)
411 blk_ver = BLK_VERSION_157;
412 #else
413 blk_ver = BLK_VERSION_110;
414 #endif
415 }
416 #endif
417
418 #if defined(CS_VERSION_155)
419 if(blk_ver == -1 && g_cs_ver == CS_VERSION_155) {
420 #if defined(BLK_VERSION_155)
421 blk_ver = BLK_VERSION_155;
422 #else
423 blk_ver = BLK_VERSION_110;
424 #endif
425 }
426 #endif
427
428 #if defined(CS_VERSION_150)
429 if(blk_ver == -1 && g_cs_ver == CS_VERSION_150) {
430 #if defined(BLK_VERSION_150)
431 blk_ver = BLK_VERSION_150;
432 #else
433 blk_ver = BLK_VERSION_110;
434 #endif
435 }
436 #endif
437
438 #if defined(CS_VERSION_125)
439 if(blk_ver == -1 && g_cs_ver == CS_VERSION_125) {
440 #if defined(BLK_VERSION_125)
441 blk_ver = BLK_VERSION_125;
442 #else
443 blk_ver = BLK_VERSION_110;
444 #endif
445 }
446 #endif
447
448 #if defined(CS_VERSION_120)
449 if(blk_ver == -1 && g_cs_ver == CS_VERSION_120) {
450 #if defined(BLK_VERSION_120)
451 blk_ver = BLK_VERSION_120;
452 #else
453 blk_ver = BLK_VERSION_110;
454 #endif
455 }
456 #endif
457
458 #if defined(CS_VERSION_110)
459 if(blk_ver == -1 && g_cs_ver == CS_VERSION_110) {
460 blk_ver = BLK_VERSION_110;
461 }
462 #endif
463
464 if(blk_ver == -1)
465 blk_ver = BLK_VERSION_100;
466
467 /*-- Initialize the command --*/
468 if (ct_command( bcp_cmd, /* Command */
469 CS_LANG_CMD, /* Type */
470 (CS_VOID*)cmd_sql, /* Buffer */
471 CS_NULLTERM, /* Buffer Length */
472 CS_UNUSED ) != CS_SUCCEED)
473 {
474 fprintf( stderr, "\\bcp: Unable to initialize command structure\n" );
475 goto return_fail;
476 }
477
478 /* sqsh-2.5 - Feature p2f, reset g_p2fc before a new batch is started */
479 g_p2fc = 0;
480
481 /*-- Send command to server --*/
482 if (ct_send( bcp_cmd ) != CS_SUCCEED)
483 {
484 fprintf( stderr, "\\bcp: Unable to send command to SQL Server\n" );
485 goto return_fail;
486 }
487
488 if (sg_interrupted)
489 goto return_interrupt;
490
491 /*
492 * If we have reached this point, then everything looks like it
493 * went OK, so it is now time to create a new connection to the
494 * destination database. Note, that we are going to share the
495 * same error handler and message handler for this connection as
496 * our parent connection.
497 */
498 if (ct_con_alloc( g_context, &bcp_con ) != CS_SUCCEED)
499 {
500 fprintf( stderr, "\\bcp: Unable to allocate new BCP connection\n" );
501 goto return_fail;
502 }
503
504 /*-- Client callback --*/
505 if (ct_callback( (CS_CONTEXT*)NULL, /* Context */
506 bcp_con, /* Connection */
507 CS_SET, /* Action */
508 CS_CLIENTMSG_CB, /* Type */
509 (CS_VOID*)bcp_client_cb /* Callback Pointer */
510 ) != CS_SUCCEED)
511 goto return_fail;
512
513 /*-- Server callback --*/
514 if (ct_callback( (CS_CONTEXT*)NULL, /* Context */
515 bcp_con, /* Connection */
516 CS_SET, /* Action */
517 CS_SERVERMSG_CB, /* Type */
518 (CS_VOID*)bcp_server_cb /* Callback Pointer */
519 ) != CS_SUCCEED)
520 goto return_fail;
521
522 /*-- Set Bulk Login --*/
523 if (ct_con_props( bcp_con, /* Connection */
524 CS_SET, /* Action */
525 CS_BULK_LOGIN, /* Property */
526 (CS_VOID*)&bcp_on, /* Buffer */
527 CS_UNUSED, /* Buffer Lenth */
528 (CS_INT*)NULL /* Output Length */
529 ) != CS_SUCCEED)
530 {
531 fprintf( stderr, "\\bcp: Unable to mark connection for BCP\n" );
532 goto return_fail;
533 }
534
535 /*-- Set username --*/
536 if (ct_con_props( bcp_con, /* Connection */
537 CS_SET, /* Action */
538 CS_USERNAME, /* Property */
539 (CS_VOID*)username, /* Buffer */
540 CS_NULLTERM, /* Buffer Lenth */
541 (CS_INT*)NULL /* Output Length */
542 ) != CS_SUCCEED)
543 {
544 fprintf( stderr,
545 "\\bcp: Unable to set username to '%s' for BCP connection\n",
546 username );
547 goto return_fail;
548 }
549
550 /*-- Set password --*/
551 if (ct_con_props( bcp_con, /* Connection */
552 CS_SET, /* Action */
553 CS_PASSWORD, /* Property */
554 (CS_VOID*)password, /* Buffer */
555 (password == NULL)?CS_UNUSED:CS_NULLTERM,
556 (CS_INT*)NULL /* Output Length */
557 ) != CS_SUCCEED)
558 {
559 fprintf( stderr, "\\bcp: Unable to set password BCP connection\n" );
560 goto return_fail;
561 }
562
563 /*-- Set application name --*/
564 if (ct_con_props( bcp_con, /* Connection */
565 CS_SET, /* Action */
566 CS_APPNAME, /* Property */
567 (CS_VOID*)"sqsh-bcp", /* Buffer */
568 CS_NULLTERM, /* Buffer Lenth */
569 (CS_INT*)NULL /* Output Length */
570 ) != CS_SUCCEED)
571 {
572 fprintf( stderr,
573 "\\bcp: Unable to set appname to 'sqsh-bcp' for BCP connection\n" );
574 goto return_fail;
575 }
576
577 /*-- Hostname --*/
578 if (hostname != NULL && *hostname != '\0') {
579 if (ct_con_props( bcp_con, /* Connection */
580 CS_SET, /* Action */
581 CS_HOSTNAME, /* Property */
582 (CS_VOID*)hostname, /* Buffer */
583 CS_NULLTERM, /* Buffer Length */
584 (CS_INT*)NULL /* Output Length */
585 ) != CS_SUCCEED)
586 {
587 fprintf( stderr,
588 "\\bcp: Unable to set hostname to '%s' for BCP connection\n",
589 hostname );
590 goto return_fail;
591 }
592 }
593
594 /*-- Packet Size --*/
595 if (packet_size != NULL) {
596 i = atoi(packet_size);
597 if (ct_con_props( bcp_con, /* Connection */
598 CS_SET, /* Action */
599 CS_PACKETSIZE, /* Property */
600 (CS_VOID*)&i, /* Buffer */
601 CS_UNUSED, /* Buffer Length */
602 (CS_INT*)NULL /* Output Length */
603 ) != CS_SUCCEED)
604 {
605 fprintf( stderr,
606 "\\bcp: Unable to set packetsize to %d for BCP connection\n",
607 (int)i );
608 goto return_fail;
609 }
610 }
611
612 /*-- Encryption --*/
613 if (encryption != NULL && *encryption == '1') {
614 i = CS_TRUE;
615 if (ct_con_props( bcp_con, /* Connection */
616 CS_SET, /* Action */
617 CS_SEC_ENCRYPTION, /* Property */
618 (CS_VOID*)&i, /* Buffer */
619 CS_UNUSED, /* Buffer Length */
620 (CS_INT*)NULL /* Output Length */
621 ) != CS_SUCCEED)
622 {
623 fprintf( stderr,
624 "\\bcp: Unable to set password encryption for BCP connection\n" );
625 goto return_fail;
626 }
627
628 #if defined (CS_SEC_EXTENDED_ENCRYPTION)
629 /*
630 * sqsh-2.1.9: Enable extended password encryption to be able to
631 * connect to ASE servers with 'net password encryption reqd'
632 * configured to 2 (RSA).
633 */
634 if (ct_con_props( bcp_con, /* Connection */
635 CS_SET, /* Action */
636 CS_SEC_EXTENDED_ENCRYPTION, /* Property */
637 (CS_VOID*)&i, /* Buffer */
638 CS_UNUSED, /* Buffer Length */
639 (CS_INT*)NULL /* Output Length */
640 ) != CS_SUCCEED)
641 {
642 fprintf( stderr,
643 "\\bcp: Unable to set extended password encryption for BCP connection\n" );
644 goto return_fail;
645 }
646 #endif
647 }
648
649 #if defined (CS_NOCHARSETCNV_REQD) && defined (BLK_CONV)
650 /*
651 * sqsh-2.2.0 - Disable character set conversion by client
652 * when in transit bulk transfer is requested (-T option)
653 */
654 if (transit == CS_TRUE)
655 {
656 char_convert = CS_TRUE;
657 if (ct_con_props( bcp_con, /* Connection */
658 CS_SET, /* Action */
659 CS_NOCHARSETCNV_REQD, /* Property */
660 (CS_VOID*)&char_convert, /* Buffer */
661 CS_UNUSED, /* Buffer Length */
662 (CS_INT*)NULL /* Output Length */
663 ) != CS_SUCCEED)
664 {
665 fprintf( stderr,
666 "\\bcp: Unable to set CS_NOCHARSETCONV_REQD for BCP connection\n" );
667 goto return_fail;
668 }
669 }
670 #endif
671
672 /*
673 * The following section initializes all locale type information.
674 * First, we need to create a locale structure and initialize it
675 * with information.
676 */
677 if (cs_loc_alloc( g_context, &bcp_locale ) != CS_SUCCEED)
678 {
679 fprintf( stderr,
680 "\\bcp: Unable to allocate locale for BCP connection\n" );
681 goto return_fail;
682 }
683
684 /*-- Initialize --*/
685 if (cs_locale( g_context, /* Context */
686 CS_SET, /* Action */
687 bcp_locale, /* Locale Structure */
688 CS_LC_ALL, /* Property */
689 (CS_CHAR*)NULL, /* Buffer */
690 CS_UNUSED, /* Buffer Length */
691 (CS_INT*)NULL /* Output Length */
692 ) != CS_SUCCEED)
693 {
694 fprintf( stderr,
695 "\\bcp: Unable to initialize locale for BCP connection\n" );
696 goto return_fail;
697 }
698
699 /*-- Language --*/
700 if( language != NULL && *language != '\0' ) {
701 if (cs_locale( g_context, /* Context */
702 CS_SET, /* Action */
703 bcp_locale, /* Locale Structure */
704 CS_SYB_LANG, /* Property */
705 (CS_CHAR*)language, /* Buffer */
706 CS_NULLTERM, /* Buffer Length */
707 (CS_INT*)NULL /* Output Length */
708 ) != CS_SUCCEED)
709 {
710 fprintf( stderr,
711 "\\bcp: Unable to set language to '%s' for BCP connection\n",
712 language );
713 goto return_fail;
714 }
715 }
716
717 /*-- Character Set --*/
718 if (charset != NULL) {
719 if (cs_locale( g_context, /* Context */
720 CS_SET, /* Action */
721 bcp_locale, /* Locale Structure */
722 CS_SYB_CHARSET, /* Property */
723 (CS_CHAR*)charset, /* Buffer */
724 CS_NULLTERM, /* Buffer Length */
725 (CS_INT*)NULL /* Output Length */
726 ) != CS_SUCCEED)
727 {
728 fprintf( stderr,
729 "\\bcp: Unable to set charset to '%s' for BCP connection\n",
730 charset );
731 goto return_fail;
732 }
733 }
734
735 /*-- Locale Property --*/
736 if (ct_con_props( bcp_con, /* Connection */
737 CS_SET, /* Action */
738 CS_LOC_PROP, /* Property */
739 (CS_VOID*)bcp_locale, /* Buffer */
740 CS_UNUSED, /* Buffer Length */
741 (CS_INT*)NULL /* Output Length */
742 ) != CS_SUCCEED)
743 {
744 fprintf( stderr, "\\bcp: Unable to set locale for BCP connection\n" );
745 goto return_fail;
746 }
747
748 #if defined(CS_SERVERADDR) && defined(CS_TDS_50)
749 if ( server != NULL && (cp = strchr(server, ':')) != NULL )
750 {
751 char *cp2;
752
753 *cp = ' ';
754 if ( (cp2 = strchr(cp+1, ':')) != NULL) /* Optional filter specified? */
755 *cp2 = ' ';
756
757 if (ct_con_props( bcp_con,
758 CS_SET,
759 CS_SERVERADDR,
760 (CS_VOID*)server,
761 CS_NULLTERM,
762 (CS_INT*)NULL
763 ) != CS_SUCCEED)
764 goto return_fail;
765
766 if (cp2 != NULL)
767 *cp2 = '\0'; /* Remove optional filter from the servername */
768 *cp = ':'; /* Put a ':' back into the display servername */
769
770 #if defined(CS_SSLVALIDATE_CB)
771 if (ct_callback( g_context, /* Context */
772 (CS_CONNECTION*)NULL, /* Connection */
773 CS_SET, /* Action */
774 CS_SSLVALIDATE_CB, /* Type */
775 (CS_VOID*)validate_srvname_cb /* Callback Pointer */
776 ) != CS_SUCCEED)
777 goto return_fail;
778 #endif
779 }
780 #endif
781
782 /*-- Now, connect --*/
783 if (ct_connect( bcp_con,
784 server,
785 (server == NULL) ? CS_UNUSED : CS_NULLTERM ) != CS_SUCCEED )
786 {
787 fprintf( stderr, "\\bcp: Unable to connect to '%s' for BCP connection\n",
788 (server == NULL) ? "NULL" : server );
789 goto return_fail;
790 }
791
792 #if defined(CTLIB_SIGPOLL_BUG) && defined(F_SETOWN)
793 /*
794 * Please refer to cmd_connect.c for detailed description of
795 * why this code is here.
796 */
797 if (ct_con_props( g_connection, /* Connection */
798 CS_GET, /* Action */
799 CS_ENDPOINT, /* Property */
800 (CS_VOID*)&ctlib_fd, /* Buffer */
801 CS_UNUSED, /* Buffer Length */
802 (CS_INT*)NULL /* Output Length */
803 ) != CS_SUCCEED)
804 {
805 fprintf( stderr, "\\bcp: WARNING: Unable to fetch CT-Lib file\n" );
806 fprintf( stderr, "\\bcp: descriptor to work around SIGPOLL bug.\n" );
807 }
808 else
809 {
810 if (fcntl( ctlib_fd, F_SETOWN, getpid() ) == -1)
811 {
812 fprintf( stderr,
813 "\\bcp: WARNING: Cannot work around CT-Lib SIGPOLL bug: %s\n",
814 strerror(errno) );
815 }
816 }
817 #endif /* CTLIB_SIGPOLL_BUG */
818
819 /*-- Inform signal handler of connection --*/
820 sg_bcp_connection = bcp_con;
821
822 /*
823 * sqsh-2.1.9 - Feature BCP execute an initialization command
824 * Process the initialization command provided in init_cmd
825 */
826 if (init_cmd != NULL)
827 {
828 if ((retcode = ct_cmd_alloc(bcp_con, &bcp_cmd_init)) != CS_SUCCEED || sg_error == True)
829 {
830 fprintf( stderr, "\\bcp: ct_cmd_alloc failed. (retcode=%d, sg_error=%d)\n", (int) retcode, sg_error );
831 goto return_fail;
832 }
833
834 if ((retcode = ct_command(bcp_cmd_init, CS_LANG_CMD, init_cmd, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) ||
835 sg_error == True)
836 {
837 fprintf( stderr, "\\bcp: ct_command() for init_cmd failed. (retcode=%d, sg_error=%d)\n",
838 (int) retcode, sg_error);
839 goto return_fail;
840 }
841
842 if ( dsp_cmd (stdout, bcp_cmd_init, init_cmd, 0) != DSP_SUCCEED || sg_error == True)
843 {
844 fprintf( stderr, "\\bcp: Execution of initialization command failed.\n");
845 goto return_fail;
846 }
847 }
848
849 /*-- Allocate a block descriptor --*/
850 DBG(sqsh_debug(DEBUG_BCP, "bcp: blk_alloc(blk_ver)\n");)
851
852 if (blk_alloc( bcp_con, blk_ver, &bcp_desc ) != CS_SUCCEED)
853 {
854 fprintf( stderr, "\\bcp: Unable to allocate bulk descriptor\n" );
855 goto return_fail;
856 }
857
858 /*
859 * Configure whether or not this connection is to contain the
860 * value for the identity column in a result set. We default
861 * this to true.
862 */
863 if (have_identity == CS_TRUE)
864 {
865 if (blk_props( bcp_desc, /* Descriptor */
866 CS_SET, /* Action */
867 BLK_IDENTITY, /* Property */
868 (CS_VOID*)&have_identity, /* Buffer */
869 CS_UNUSED, /* Buffer Length*/
870 (CS_INT*)NULL /* Output Length */
871 ) != CS_SUCCEED)
872 {
873 fprintf( stderr, "\\bcp: Unable to set BLK_IDENTITY option to %s\n",
874 have_identity == CS_TRUE ? "CS_TRUE" : "CS_FALSE" );
875 goto return_fail;
876 }
877 }
878
879 #if defined (CS_NOCHARSETCNV_REQD) && defined (BLK_CONV)
880 /*
881 * sqsh-2.2.0 - Disable character set conversion by client
882 * when in transit bulk transfer is requested (-T option)
883 */
884 if (transit == CS_TRUE)
885 {
886 char_convert = CS_FALSE;
887 if (blk_props( bcp_desc, /* Descriptor */
888 CS_SET, /* Action */
889 BLK_CONV, /* Property */
890 (CS_VOID*)&char_convert, /* Buffer */
891 CS_UNUSED, /* Buffer Length*/
892 (CS_INT*)NULL /* Output Length */
893 ) != CS_SUCCEED)
894 {
895 fprintf( stderr, "\\bcp: Unable to set BLK_CONV option to CS_FALSE\n");
896 goto return_fail;
897 }
898 }
899 #endif
900
901 /*
902 * sqsh-2.2.0 - Feature enable BCP_IN into a specific partition of a partitioned table
903 */
904 if (bcp_partition != NULL)
905 {
906 if (isdigit( (int) *bcp_partition))
907 {
908 bcp_slicenum = atoi (bcp_partition);
909 #if defined (BLK_SLICENUM)
910 if (blk_props( bcp_desc, /* Descriptor */
911 CS_SET, /* Action */
912 BLK_SLICENUM, /* Property */
913 (CS_VOID*)&bcp_slicenum, /* Buffer */
914 CS_UNUSED, /* Buffer Length*/
915 (CS_INT*)NULL /* Output Length */
916 ) != CS_SUCCEED)
917 {
918 fprintf( stderr, "\\bcp: Unable to set BLK_SLICENUM option\n");
919 goto return_fail;
920 }
921 #else
922 fprintf(stderr, "\\bcp: The build version of Bulk Library does not (fully) support table partitioning.\n");
923 fprintf(stderr, "\\bcp: The specified slice number '%d' will be ignored.\n", bcp_slicenum);
924 #endif
925 }
926 else
927 {
928 #if defined (BLK_PARTITION)
929 if (blk_props( bcp_desc, /* Descriptor */
930 CS_SET, /* Action */
931 BLK_PARTITION, /* Property */
932 (CS_VOID*)bcp_partition, /* Buffer */
933 strlen(bcp_partition), /* Buffer Length*/
934 (CS_INT*)NULL /* Output Length */
935 ) != CS_SUCCEED)
936 {
937 fprintf( stderr, "\\bcp: Unable to set BLK_PARTITION option\n");
938 goto return_fail;
939 }
940 #else
941 fprintf(stderr, "\\bcp: The build version of Bulk Library does not (fully) support table partitioning.\n");
942 fprintf(stderr, "\\bcp: The specified partition name '%s' will be ignored.\n", bcp_partition);
943 #endif
944 }
945 }
946
947 /*-- Initialize the bulk copy --*/
948 DBG(sqsh_debug(DEBUG_BCP, "bcp: blk_init(CS_BLK_IN,'%s',%d)\n",
949 bcp_table, strlen(bcp_table));)
950
951 if (blk_init( bcp_desc, CS_BLK_IN, bcp_table,
952 strlen(bcp_table) ) != CS_SUCCEED)
953 {
954 fprintf( stderr, "\\bcp: Unable to initialize bulk copy on table '%s'\n",
955 bcp_table );
956 goto return_fail;
957 }
958
959 fprintf(stderr, "\nStarting copy...\n" );
960
961 /*
962 * Allrightythen. We have already sent the command to retrieve
963 * data through g_dbproc, and have succesfully created bcp_dbproc
964 * in order to jam the data into another database, so lets start
965 * processing results.
966 */
967 rows_in_batch = 0;
968 nerrors = 0;
969
970 while ((return_code = ct_results( bcp_cmd, &result_type ))
971 != CS_END_RESULTS)
972 {
973 if (sg_interrupted)
974 goto return_interrupt;
975
976 if (return_code != CS_SUCCEED)
977 break;
978
979 switch (result_type)
980 {
981 case CS_ROW_RESULT:
982
983 /*-- Destroy old data --*/
984 if (bcp_dat != NULL)
985 {
986 bcp_data_destroy( bcp_dat );
987 }
988
989 /*-- Create new data --*/
990 if ((bcp_dat = bcp_data_bind( bcp_cmd, result_type )) == NULL)
991 goto return_fail;
992
993 while ((return_code =
994 bcp_data_xfer( bcp_dat,
995 bcp_cmd,
996 bcp_desc )) != CS_END_DATA)
997 {
998 if (sg_interrupted)
999 goto return_interrupt;
1000
1001 if (return_code != CS_SUCCEED)
1002 {
1003 DBG(sqsh_debug(DEBUG_BCP, "bcp: bcp_data_xfer failed...\n");)
1004
1005 if (++nerrors == maxerrors)
1006 goto return_fail;
1007 }
1008 else
1009 {
1010 ++rows_in_batch;
1011 }
1012
1013 if (rows_in_batch == batchsize)
1014 {
1015 DBG(sqsh_debug(DEBUG_BCP, "bcp: blk_done(CS_BLK_BATCH)\n");)
1016
1017 if (blk_done( bcp_desc,
1018 CS_BLK_BATCH,
1019 &nrows ) != CS_SUCCEED)
1020 {
1021 DBG(sqsh_debug(DEBUG_BCP, "bcp: blk_done failed!\n");)
1022
1023 if (++nerrors == maxerrors)
1024 goto return_fail;
1025 }
1026 else
1027 {
1028 total_rows += rows_in_batch;
1029
1030 fprintf(stderr,
1031 "Batch successfully bulk-copied to SQL Server.\n");
1032 }
1033
1034 if (sg_interrupted)
1035 goto return_interrupt;
1036
1037 rows_in_batch = 0;
1038 }
1039 } /* while (bcp_data_xfer()) */
1040 break;
1041
1042 case CS_PARAM_RESULT:
1043 case CS_STATUS_RESULT:
1044 case CS_COMPUTE_RESULT:
1045 while ((return_code = ct_fetch( bcp_cmd, CS_UNUSED, CS_UNUSED,
1046 CS_UNUSED, &nrows )) == CS_SUCCEED);
1047
1048 if (return_code != CS_END_DATA)
1049 {
1050 fprintf( stderr,
1051 "\\bcp: Error discarding extraneous result sets\n" );
1052
1053 goto return_fail;
1054 }
1055 break;
1056
1057 default:
1058 break;
1059 } /* switch (result_type) */
1060
1061 }
1062
1063 if (rows_in_batch > 0)
1064 {
1065 DBG(sqsh_debug(DEBUG_BCP, "bcp: FINAL: blk_done(CS_BLK_BATCH)\n");)
1066 if (blk_done( bcp_desc,
1067 CS_BLK_BATCH,
1068 &nrows ) != CS_SUCCEED)
1069 {
1070 goto return_fail;
1071 }
1072
1073 if (sg_interrupted)
1074 goto return_interrupt;
1075
1076 if (nrows != rows_in_batch)
1077 {
1078 if (++nerrors == maxerrors)
1079 goto return_fail;
1080 }
1081 total_rows += nrows;
1082 }
1083
1084 DBG(sqsh_debug(DEBUG_BCP, "bcp: blk_done(CS_BLK_ALL)\n");)
1085 if (blk_done( bcp_desc,
1086 CS_BLK_ALL,
1087 &nrows ) != CS_SUCCEED)
1088 goto return_fail;
1089
1090 gettimeofday( &tv_end, NULL );
1091
1092 if (rows_in_batch != 0)
1093 fprintf(stderr,"Batch successfully bulk-copied to SQL Server\n");
1094
1095 fprintf( stderr, "\n%d row%s copied.\n", total_rows,
1096 (total_rows != 1) ? "s" : "" );
1097
1098 /* add check for non-zero number of rows passed to avoid
1099 potential division by 0 error.
1100 patch by Onno van der Linden */
1101 if(total_rows > 0) {
1102 secs = ELAPSED_SEC(tv_start,tv_end);
1103 fprintf( stderr,
1104 "Clock Time (sec.): Total = %-.4f Avg = %-.4f (%.2f rows per sec.)\n",
1105 secs, secs / (double)total_rows, (double)total_rows / secs );
1106 }
1107
1108 return_code = CMD_RESETBUF;
1109 goto leave;
1110
1111 return_interrupt:
1112 if (bcp_desc != NULL)
1113 blk_done( bcp_desc, CS_BLK_CANCEL, &nrows );
1114 ct_cancel( bcp_con, (CS_COMMAND*)NULL, CS_CANCEL_ALL );
1115 ct_cancel( g_connection, (CS_COMMAND*)NULL, CS_CANCEL_ALL );
1116
1117 return_code = CMD_RESETBUF;
1118 goto leave;
1119
1120 return_fail:
1121 DBG(sqsh_debug(DEBUG_ERROR, "bcp: Failure encountered, cleaning up.\n");)
1122
1123 if (bcp_con != NULL)
1124 {
1125 if (ct_con_props( bcp_con, /* Connection */
1126 CS_GET, /* Action */
1127 CS_CON_STATUS, /* Property */
1128 (CS_VOID*)&con_status, /* Buffer */
1129 CS_UNUSED, /* Buffer Length */
1130 (CS_INT*)NULL ) != CS_SUCCEED)
1131 {
1132 DBG(sqsh_debug(DEBUG_ERROR, "bcp: Unable to get con status.\n");)
1133 con_status = CS_CONSTAT_CONNECTED;
1134 }
1135
1136 /*-- If connected, disconnect --*/
1137 if (con_status == CS_CONSTAT_CONNECTED)
1138 {
1139 if (bcp_desc != NULL)
1140 {
1141 DBG(sqsh_debug(DEBUG_ERROR, "bcp: Cancelling bcp batch.\n");)
1142 blk_done( bcp_desc, CS_BLK_CANCEL, &nrows );
1143 }
1144
1145 DBG(sqsh_debug(DEBUG_ERROR, "bcp: Cancelling bcp connection.\n");)
1146 ct_cancel( bcp_con, (CS_COMMAND*)NULL, CS_CANCEL_ALL );
1147
1148 DBG(sqsh_debug(DEBUG_ERROR, "bcp: Closing bcp connection.\n");)
1149 if (ct_close( bcp_con, CS_UNUSED ) != CS_SUCCEED)
1150 ct_close( bcp_con, CS_FORCE_CLOSE );
1151 }
1152
1153 ct_con_drop( bcp_con );
1154 bcp_con = NULL;
1155 }
1156
1157 if (g_connection != NULL)
1158 {
1159 if (ct_con_props( g_connection, /* Connection */
1160 CS_GET, /* Action */
1161 CS_CON_STATUS, /* Property */
1162 (CS_VOID*)&con_status, /* Buffer */
1163 CS_UNUSED, /* Buffer Length */
1164 (CS_INT*)NULL ) != CS_SUCCEED)
1165 {
1166 DBG(sqsh_debug(DEBUG_ERROR, "bcp: Unable to get con status.\n");)
1167 con_status = CS_CONSTAT_CONNECTED;
1168 }
1169
1170 if (con_status == CS_CONSTAT_CONNECTED)
1171 {
1172 DBG(sqsh_debug(DEBUG_ERROR, "bcp: Cancelling result set.\n");)
1173 ct_cancel( g_connection, (CS_COMMAND*)NULL, CS_CANCEL_ALL );
1174 }
1175 else
1176 {
1177 DBG(sqsh_debug(DEBUG_ERROR, "bcp: Connection dead.\n");)
1178 }
1179 }
1180
1181 return_code = CMD_FAIL;
1182
1183 leave:
1184 if (bcp_dat != NULL)
1185 bcp_data_destroy( bcp_dat );
1186
1187 if (exp_buf != NULL)
1188 varbuf_destroy( exp_buf );
1189
1190 if (bcp_cmd != NULL)
1191 ct_cmd_drop( bcp_cmd );
1192
1193 if (bcp_cmd_init != NULL)
1194 ct_cmd_drop( bcp_cmd_init );
1195
1196 if (bcp_desc != NULL)
1197 {
1198 DBG(sqsh_debug(DEBUG_BCP, "bcp: blk_drop()\n");)
1199 blk_drop( bcp_desc );
1200 }
1201
1202 if (bcp_con != NULL)
1203 {
1204 if (ct_close( bcp_con, CS_UNUSED ) != CS_SUCCEED)
1205 ct_close( bcp_con, CS_FORCE_CLOSE );
1206 ct_con_drop( bcp_con );
1207 }
1208
1209 if (bcp_locale != NULL)
1210 cs_loc_drop( g_context, bcp_locale );
1211
1212 sig_restore();
1213 return return_code;
1214 }
1215
bcp_data_bind(cmd,result_type)1216 static bcp_data_t* bcp_data_bind ( cmd, result_type )
1217 CS_COMMAND *cmd;
1218 CS_INT result_type;
1219 {
1220 CS_INT ncols;
1221 CS_INT i;
1222 bcp_data_t *d;
1223 bcp_col_t *c;
1224
1225 /*-- Retrieve the number of columns in the result set --*/
1226 if (ct_res_info( cmd, /* Command */
1227 CS_NUMDATA, /* Type */
1228 (CS_VOID*)&ncols, /* Buffer */
1229 CS_UNUSED, /* Buffer Length */
1230 (CS_INT*)NULL) != CS_SUCCEED)
1231 {
1232 fprintf( stderr, "bcp_data_bind: Unable to fetch number of columns\n" );
1233 return NULL;
1234 }
1235
1236 /*-- Fix for bug report 2920048, using calloc instead of malloc --*/
1237 d = (bcp_data_t*)calloc( 1, sizeof( bcp_data_t ) );
1238 c = (bcp_col_t*)calloc( ncols, sizeof( bcp_col_t ) );
1239
1240 if (d == NULL || c == NULL)
1241 {
1242 fprintf( stderr, "bcp_data_bind: Memory allocation failure.\n" );
1243 if (d != NULL)
1244 free( d );
1245 if (c != NULL)
1246 free( c );
1247 return NULL;
1248 }
1249
1250 /*-- Inialize d --*/
1251 d->d_type = result_type;
1252 d->d_ncols = ncols;
1253 d->d_cols = c;
1254
1255 for (i = 0; i < ncols; i++)
1256 d->d_cols[i].c_data = NULL;
1257
1258 for (i = 0; i < ncols; i++)
1259 {
1260 c = &d->d_cols[i];
1261 c->c_colid = i + 1;
1262 c->c_len = -1;
1263 c->c_nullind = 0;
1264
1265 /*-- Get description for column --*/
1266 if (ct_describe( cmd, i+1, &c->c_format ) != CS_SUCCEED)
1267 {
1268 fprintf( stderr,
1269 "bcp_data_bind: Unable to fetch column %d description\n",
1270 (int) i+1 );
1271 bcp_data_destroy( d );
1272 return NULL;
1273 }
1274
1275 /*-- Allocate enough space to hold data --*/
1276 /*-- Fix for bug report 2920048, using calloc instead of malloc --*/
1277 c->c_data = (CS_VOID*)calloc( 1, c->c_format.maxlength );
1278
1279 /*-- Clean up format --*/
1280 c->c_format.count = 1;
1281 c->c_format.locale = NULL;
1282
1283 /*-- Bind to the data space --*/
1284 if (ct_bind( cmd, /* Command */
1285 i + 1, /* Item */
1286 &c->c_format, /* Format */
1287 (CS_VOID*)c->c_data, /* Buffer */
1288 (CS_INT*)&c->c_len, /* Data Copied */
1289 &c->c_nullind /* NULL Indicator */
1290 ) != CS_SUCCEED)
1291 {
1292 fprintf( stderr,
1293 "bcp_data_bind: Unable to bind column %d\n",
1294 (int) i+1 );
1295 bcp_data_destroy( d );
1296 return NULL;
1297 }
1298 }
1299
1300 return d;
1301 }
1302
bcp_data_xfer(d,cmd,blkdesc)1303 static CS_INT bcp_data_xfer( d, cmd, blkdesc )
1304 bcp_data_t *d;
1305 CS_COMMAND *cmd;
1306 CS_BLKDESC *blkdesc;
1307 {
1308 CS_RETCODE return_code;
1309 CS_INT nrows;
1310 CS_INT i;
1311 bcp_col_t *c;
1312
1313 return_code = ct_fetch( cmd, /* Command */
1314 CS_UNUSED, /* Type */
1315 CS_UNUSED, /* Offset */
1316 CS_UNUSED, /* Option */
1317 &nrows );
1318
1319 if (return_code != CS_SUCCEED)
1320 {
1321 return return_code;
1322 }
1323
1324 for (i = 0; i < d->d_ncols; i++)
1325 {
1326 c = &d->d_cols[i];
1327
1328 /*
1329 * Here we determine whether or not we need to (re-) bind to
1330 * the incoming data. If the length of the data has changed
1331 * since the last row, or if it has become NULL, then we
1332 * want to re-bind.
1333 */
1334 if (c->c_len == -1 || c->c_len != c->c_prevlen ||
1335 c->c_nullind != c->c_prevnullind)
1336 {
1337 DBG(sqsh_debug(DEBUG_BCP,
1338 "bcp: blk_bind( %d, DATAFMT, %d, %d )\n",
1339 (int)i + 1, (int)c->c_len, (int)c->c_nullind);)
1340
1341 if (c->c_nullind == -1)
1342 {
1343 c->c_len = 0;
1344 }
1345
1346 c->c_prevlen = c->c_len;
1347 c->c_prevnullind = c->c_nullind;
1348
1349 if (blk_bind( blkdesc, /* Block Descriptor */
1350 i + 1, /* Column Number */
1351 &c->c_format, /* Data Format */
1352 (CS_VOID*)c->c_data, /* Buffer */
1353 &c->c_len, /* Buffer Length */
1354 &c->c_nullind ) != CS_SUCCEED)
1355 {
1356 fprintf( stderr,
1357 "bcp_data_xfer: Unable to bind results for column %d\n",
1358 (int) i+1 );
1359 return CS_FAIL;
1360 }
1361 }
1362 }
1363
1364 DBG(sqsh_debug(DEBUG_BCP, "bcp: blk_rowxfer()\n");)
1365 if (blk_rowxfer( blkdesc ) != CS_SUCCEED)
1366 {
1367 fprintf( stderr,
1368 "bcp_data_xfer: Unable to transfer row to remote SQL Server\n" );
1369 return CS_FAIL;
1370 }
1371
1372 return CS_SUCCEED;
1373 }
1374
1375 /*
1376 * bcp_data_destroy():
1377 *
1378 * Destroys a bcp_data_t structure.
1379 */
bcp_data_destroy(d)1380 static void bcp_data_destroy( d )
1381 bcp_data_t *d;
1382 {
1383 CS_INT i;
1384
1385 if (d != NULL)
1386 {
1387 if (d->d_cols != NULL)
1388 {
1389 for (i = 0; i < d->d_ncols; i++)
1390 {
1391 if (d->d_cols[i].c_data != NULL)
1392 free( d->d_cols[i].c_data );
1393 }
1394
1395 free( d->d_cols );
1396 }
1397
1398 free( d );
1399 }
1400 }
1401
1402 /*
1403 * bcp_signal():
1404 *
1405 * This function is called whenever a signal is received, its
1406 * only real job is to register the fact that a signal was caught
1407 * during processing via the sg_interrupted flag.
1408 */
bcp_signal(sig,user_data)1409 static void bcp_signal( sig, user_data )
1410 int sig;
1411 void *user_data;
1412 {
1413 sg_interrupted = True;
1414
1415 if (sg_bcp_connection != NULL)
1416 {
1417 ct_cancel( sg_bcp_connection, (CS_COMMAND*)NULL, CS_CANCEL_ATTN );
1418 }
1419 ct_cancel( g_connection, (CS_COMMAND*)NULL, CS_CANCEL_ALL );
1420 }
1421
1422
1423 /*
1424 * bcp_server_cb():
1425 *
1426 * Sybase callback message handler for all messages coming from the
1427 * SQL Server or Open Server.
1428 *
1429 */
bcp_server_cb(ctx,con,msg)1430 static CS_RETCODE bcp_server_cb (ctx, con, msg)
1431 CS_CONTEXT *ctx;
1432 CS_CONNECTION *con;
1433 CS_SERVERMSG *msg;
1434 {
1435 /*
1436 * Ignore "database changed", or "language changed" messages from
1437 * the server.
1438 */
1439 if( msg->msgnumber == 5701 || /* database context change */
1440 msg->msgnumber == 5703 || /* language changed */
1441 msg->msgnumber == 5704 ) /* charset changed */
1442 {
1443 return CS_SUCCEED;
1444 }
1445
1446 if (msg->severity >= 0)
1447 {
1448 /*
1449 * If the severity is something other than 0 or the msg number is
1450 * 0 (user informational messages).
1451 */
1452 if (msg->severity >= 0 || msg->msgnumber == 0)
1453 {
1454 /*
1455 * If the message was something other than informational, and
1456 * the severity was greater than 0, then print information to
1457 * stderr with a little pre-amble information. According to
1458 * the Sybase System Administrator's guide, severity level 10
1459 * messages should not display severity information.
1460 */
1461 if (msg->msgnumber > 0 && msg->severity > 10)
1462 {
1463 fprintf( stderr, "Msg %d, Level %d, State %d\n",
1464 (int)msg->msgnumber, (int)msg->severity, (int)msg->state );
1465 if (msg->svrnlen > 0)
1466 fprintf( stderr, "Server '%s'", (char*)msg->svrname );
1467 if (msg->proclen > 0)
1468 fprintf( stderr, ", Procedure '%s'", (char*)msg->proc );
1469 if( msg->line > 0 )
1470 fprintf( stderr, ", Line %d", (int)msg->line );
1471 fprintf( stderr, "\n" );
1472 fprintf( stderr, "%s\n", msg->text );
1473 fflush( stderr );
1474
1475 sg_error = True;
1476 }
1477 else
1478 {
1479 /*
1480 * Otherwise, it is just an informational (e.g. print) message
1481 * from the server, so send it to stdout.
1482 */
1483 fprintf( stdout, "%s\n", msg->text );
1484 fflush( stdout );
1485 }
1486 }
1487 }
1488
1489 return CS_SUCCEED;
1490 }
1491
1492 /*
1493 * bcp_client_cb():
1494 */
bcp_client_cb(ctx,con,msg)1495 static CS_RETCODE bcp_client_cb ( ctx, con, msg )
1496 CS_CONTEXT *ctx;
1497 CS_CONNECTION *con;
1498 CS_CLIENTMSG *msg;
1499 {
1500 /*
1501 * Let the CS-Lib handler print the message out.
1502 */
1503 fprintf( stderr, "Open Client Message\n" );
1504 if (CS_NUMBER(msg->msgnumber) > 0)
1505 {
1506 fprintf( stderr, "Layer %d, Origin %d, Severity %d, Number %d\n",
1507 (int)CS_LAYER(msg->msgnumber),
1508 (int)CS_ORIGIN(msg->msgnumber),
1509 (int)CS_SEVERITY(msg->msgnumber),
1510 (int)CS_NUMBER(msg->msgnumber) );
1511 }
1512 if (msg->osstringlen > 0)
1513 {
1514 fprintf( stderr, "OS Error: %s\n", (char*)msg->osstring );
1515 }
1516 fprintf( stderr, "%s\n", msg->msgstring );
1517 fflush( stderr ) ;
1518
1519 sg_error = True;
1520
1521 return CS_SUCCEED ;
1522 }
1523
1524 #if defined(CS_SSLVALIDATE_CB)
1525 /*
1526 * sqsh-2.5 - Validate the servername in a host:port:ssl type of connection
1527 * to be valid for the chosen certificate if the servername does
1528 * not match the CN in the certificate.
1529 */
validate_srvname_cb(userdata,certptr,certcount,valid)1530 static CS_RETCODE validate_srvname_cb (userdata, certptr, certcount, valid)
1531 CS_VOID *userdata;
1532 CS_SSLCERT *certptr;
1533 CS_INT certcount;
1534 CS_INT valid;
1535 {
1536 if (valid == CS_SSL_INVALID_MISMATCHNAME)
1537 {
1538 return CS_SSL_VALID_CERT;
1539 }
1540 else
1541 {
1542 return valid;
1543 }
1544 }
1545 #endif
1546
1547