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