6666
6767#include "freebcp.h"
6868
69+ enum
70+ {
71+ BCPFORMAT_NONE , BCPFORMAT_CHARACTER , BCPFORMAT_NATIVE , BCPFORMAT_FORMATTED
72+ };
73+ typedef int BCPFORMAT ;
74+
6975int tdsdump_open (const char * filename );
7076
7177static void pusage (void );
7278static int process_parameters (int , char * * , BCPPARAMDATA * );
7379static int unescape (char arg []);
7480static int login_to_database (BCPPARAMDATA * pdata , DBPROCESS * * pdbproc );
7581
76- static int file_character (BCPPARAMDATA * pdata , DBPROCESS * dbproc , DBINT dir );
77- static int file_native (BCPPARAMDATA * pdata , DBPROCESS * dbproc , DBINT dir );
78- static int file_formatted (BCPPARAMDATA * pdata , DBPROCESS * dbproc , DBINT dir );
7982static int setoptions (DBPROCESS * dbproc , BCPPARAMDATA * params );
80-
83+ static BCPFORMAT get_format (BCPPARAMDATA * params );
84+ static int file_process (BCPPARAMDATA * pdata , DBPROCESS * dbproc , DBINT dir );
8185static int err_handler (DBPROCESS * dbproc , int severity , int dberr , int oserr , char * dberrstr , char * oserrstr );
8286static int msg_handler (DBPROCESS * dbproc TDS_UNUSED , DBINT msgno , int msgstate , int severity , char * msgtext , char * srvname ,
8387 char * procname , int line );
@@ -116,21 +120,27 @@ main(int argc, char **argv)
116120 if (!setoptions (dbproc , & params ))
117121 return FALSE;
118122
119- if (params .cflag ) { /* character format file */
120- ok = file_character (& params , dbproc , params .direction );
121- } else if (params .nflag ) { /* native format file */
122- ok = file_native (& params , dbproc , params .direction );
123- } else if (params .fflag ) { /* formatted file */
124- ok = file_formatted (& params , dbproc , params .direction );
125- } else {
126- ok = FALSE;
127- }
123+ ok = file_process (& params , dbproc , params .direction );
128124
129125 exit ((ok == TRUE) ? EXIT_SUCCESS : EXIT_FAILURE );
130126
131127 return 0 ;
132128}
133129
130+ static BCPFORMAT
131+ get_format (BCPPARAMDATA * params )
132+ {
133+ if (params -> cflag )
134+ return BCPFORMAT_CHARACTER ;
135+
136+ if (params -> nflag )
137+ return BCPFORMAT_NATIVE ;
138+
139+ if (params -> fflag )
140+ return BCPFORMAT_FORMATTED ;
141+
142+ return BCPFORMAT_NONE ;
143+ }
134144
135145static int unescape (char arg [])
136146{
@@ -478,62 +488,39 @@ login_to_database(BCPPARAMDATA *pdata, DBPROCESS **pdbproc)
478488
479489}
480490
481- static int
482- file_character (BCPPARAMDATA * pdata , DBPROCESS * dbproc , DBINT dir )
491+ static RETCODE
492+ format_column (BCPPARAMDATA * pdata , DBPROCESS * dbproc , BCPFORMAT file_format , int i , int is_last_column )
483493{
484- DBINT li_rowsread = 0 ;
485- int i ;
486- int li_numcols = 0 ;
487-
488- if (FAIL == bcp_init (dbproc , pdata -> dbobject , pdata -> hostfilename , pdata -> errorfile , dir ))
489- return FALSE;
494+ int li_coltype = SYBCHAR ;
495+ int host_prefixlen = 0 ;
496+ char * host_term = NULL ;
497+ int host_termlen = -1 ;
490498
491- if (!set_bcp_hints (pdata , dbproc ))
492- return FALSE;
493-
494- bcp_control (dbproc , BCPFIRST , pdata -> firstrow );
495- bcp_control (dbproc , BCPLAST , pdata -> lastrow );
496- bcp_control (dbproc , BCPMAXERRS , pdata -> maxerrors );
497-
498- /* Reformat columns to SYBCHAR instead of native type, and add column and row terminator strings */
499- li_numcols = bcp_gethostcolcount (dbproc );
500- for (i = 1 ; i < li_numcols ; ++ i ) {
501- if (bcp_colfmt (dbproc , i , SYBCHAR , 0 , -1 , (const BYTE * ) pdata -> fieldterm ,
502- pdata -> fieldtermlen , i ) == FAIL ) {
503- fprintf (stderr , "Error in bcp_colfmt col %d\n" , i );
504- return FALSE;
505- }
506- }
507-
508- if (bcp_colfmt (dbproc , li_numcols , SYBCHAR , 0 , -1 , (const BYTE * ) pdata -> rowterm ,
509- pdata -> rowtermlen , li_numcols ) == FAIL ) {
510- fprintf (stderr , "Error in bcp_colfmt col %d\n" , li_numcols );
511- return FALSE;
512- }
513-
514- bcp_control (dbproc , BCPBATCH , pdata -> batchsize );
515- if (!process_Eflag (pdata , dbproc ))
516- return FALSE;
517-
518- printf ("\nStarting copy...\n" );
519-
520- if (FAIL == bcp_exec (dbproc , & li_rowsread )) {
521- fprintf (stderr , "bcp copy %s failed\n" , (dir == DB_IN ) ? "in" : "out" );
522- return FALSE;
499+ if (file_format == BCPFORMAT_NATIVE ) {
500+ li_coltype = dbcoltype (dbproc , i );
501+ host_prefixlen = -1 ;
502+ } else if (is_last_column ) {
503+ host_term = pdata -> rowterm ;
504+ host_termlen = pdata -> rowtermlen ;
505+ } else {
506+ host_term = pdata -> fieldterm ;
507+ host_termlen = pdata -> fieldtermlen ;
523508 }
524509
525- printf ("%d rows copied.\n" , li_rowsread );
526-
527- return TRUE;
510+ return bcp_colfmt (dbproc , i , li_coltype , host_prefixlen , -1 , (const BYTE * ) host_term , host_termlen , i );
528511}
529512
530513static int
531- file_native (BCPPARAMDATA * pdata , DBPROCESS * dbproc , DBINT dir )
514+ file_process (BCPPARAMDATA * pdata , DBPROCESS * dbproc , DBINT dir )
532515{
533516 DBINT li_rowsread = 0 ;
534517 int i ;
535- int li_numcols = 0 ;
536- int li_coltype ;
518+ int li_numcols ;
519+
520+ BCPFORMAT file_format = get_format (pdata );
521+
522+ if (file_format == BCPFORMAT_NONE )
523+ return FALSE;
537524
538525 if (FAIL == bcp_init (dbproc , pdata -> dbobject , pdata -> hostfilename , pdata -> errorfile , dir ))
539526 return FALSE;
@@ -545,61 +532,39 @@ file_native(BCPPARAMDATA *pdata, DBPROCESS *dbproc, DBINT dir)
545532 bcp_control (dbproc , BCPLAST , pdata -> lastrow );
546533 bcp_control (dbproc , BCPMAXERRS , pdata -> maxerrors );
547534
548- li_numcols = bcp_gethostcolcount (dbproc );
549-
550- /* The data file does not use TDS nullable types. It uses non-nullable
551- * representations, and a Length prefix if the target column was nullable.
552- * The length prefix typically takes value 0 or -1 to indicate a null.
553- */
554- for (i = 1 ; i <= li_numcols ; i ++ ) {
555- li_coltype = dbcoltype (dbproc , i );
556-
557- if (bcp_colfmt (dbproc , i , li_coltype , -1 , -1 , NULL , -1 , i ) == FAIL ) {
558- fprintf (stderr , "Error in bcp_colfmt col %d\n" , i );
535+ switch (file_format ) {
536+ case BCPFORMAT_FORMATTED :
537+ if (FAIL == bcp_readfmt (dbproc , pdata -> formatfile ))
559538 return FALSE;
539+ break ;
540+
541+ /* The data file does not use TDS nullable types. It uses non-nullable
542+ * representations, and a Length prefix if the target column was nullable.
543+ * The length prefix typically takes value 0 or -1 to indicate a null.
544+ * So, we need to check format of all columns.
545+ */
546+ case BCPFORMAT_NATIVE :
547+ case BCPFORMAT_CHARACTER :
548+ li_numcols = bcp_gethostcolcount (dbproc );
549+ for (i = 1 ; i <= li_numcols ; ++ i ) {
550+ if (format_column (pdata , dbproc , file_format , i , i == li_numcols ) == FAIL ) {
551+ fprintf (stderr , "Error in bcp_colfmt col %d\n" , i );
552+ return FALSE;
553+ }
560554 }
555+ break ;
561556 }
562557
563- if (!process_Eflag (pdata , dbproc ))
564- return FALSE;
565-
566- printf ("\nStarting copy...\n\n" );
567-
568- if (FAIL == bcp_exec (dbproc , & li_rowsread )) {
569- fprintf (stderr , "bcp copy %s failed\n" , (dir == DB_IN ) ? "in" : "out" );
570- return FALSE;
571- }
572-
573- printf ("%d rows copied.\n" , li_rowsread );
574-
575- return TRUE;
576- }
577-
578- static int
579- file_formatted (BCPPARAMDATA * pdata , DBPROCESS * dbproc , DBINT dir )
580- {
581-
582- int li_rowsread ;
583-
584- if (FAIL == bcp_init (dbproc , pdata -> dbobject , pdata -> hostfilename , pdata -> errorfile , dir ))
585- return FALSE;
586-
587- if (!set_bcp_hints (pdata , dbproc ))
588- return FALSE;
558+ if (file_format == BCPFORMAT_CHARACTER )
559+ bcp_control (dbproc , BCPBATCH , pdata -> batchsize );
589560
561+ /* note: process_Eflag frees data needed by format_column() for NATIVE type,
562+ * so call this after the column loop. */
590563 if (!process_Eflag (pdata , dbproc ))
591564 return FALSE;
592565
593- bcp_control (dbproc , BCPFIRST , pdata -> firstrow );
594- bcp_control (dbproc , BCPLAST , pdata -> lastrow );
595- bcp_control (dbproc , BCPMAXERRS , pdata -> maxerrors );
596-
597- if (FAIL == bcp_readfmt (dbproc , pdata -> formatfile ))
598- return FALSE;
599-
600566 printf ("\nStarting copy...\n\n" );
601567
602-
603568 if (FAIL == bcp_exec (dbproc , & li_rowsread )) {
604569 fprintf (stderr , "bcp copy %s failed\n" , (dir == DB_IN ) ? "in" : "out" );
605570 return FALSE;
0 commit comments