LCOV - code coverage report
Current view: top level - src/dblib - bcp.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 653 962 67.9 %
Date: 2026-07-19 14:02:14 Functions: 31 35 88.6 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Brian Bruns
       3             :  * Copyright (C) 2010, 2011  Frediano Ziglio
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or
       6             :  * modify it under the terms of the GNU Library General Public
       7             :  * License as published by the Free Software Foundation; either
       8             :  * version 2 of the License, or (at your option) any later version.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * Library General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU Library General Public
      16             :  * License along with this library; if not, write to the
      17             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      18             :  * Boston, MA 02111-1307, USA.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : 
      23             : #include <stdarg.h>
      24             : #include <stdio.h>
      25             : #include <assert.h>
      26             : 
      27             : #if HAVE_STRING_H
      28             : #include <string.h>
      29             : #endif /* HAVE_STRING_H */
      30             : 
      31             : #if HAVE_STDLIB_H
      32             : #include <stdlib.h>
      33             : #endif /* HAVE_STDLIB_H */
      34             : 
      35             : #if HAVE_UNISTD_H
      36             : #include <unistd.h>
      37             : #endif /* HAVE_UNISTD_H */
      38             : 
      39             : #ifdef _WIN32
      40             : #include <io.h>
      41             : #endif
      42             : 
      43             : #include <freetds/tds.h>
      44             : #include <freetds/tds/checks.h>
      45             : #include <freetds/tds/iconv.h>
      46             : #include <freetds/tds/convert.h>
      47             : #include <freetds/bytes.h>
      48             : #include <freetds/tds/stream.h>
      49             : #include <freetds/utils/string.h>
      50             : #include <freetds/encodings.h>
      51             : #include <freetds/replacements.h>
      52             : #include <sybfront.h>
      53             : #include <sybdb.h>
      54             : #include <syberror.h>
      55             : #include <dblib.h>
      56             : 
      57             : #define BCP_DEFAULT_DATEFMT "%Y-%m-%d %H:%M:%S.%z"
      58             : 
      59             : #define HOST_COL_CONV_ERROR 1
      60             : #define HOST_COL_NULL_ERROR 2
      61             : 
      62             : static void _bcp_free_storage(DBPROCESS * dbproc);
      63             : static void _bcp_free_columns(DBPROCESS * dbproc);
      64             : static void _bcp_null_error(TDSBCPINFO * bcpinfo, int index, int offset);
      65             : static TDSRET _bcp_get_col_data(TDSBCPINFO * bcpinfo, TDSCOLUMN * bindcol, int index, int offset);
      66             : static TDSRET _bcp_no_get_col_data(TDSBCPINFO * bcpinfo, TDSCOLUMN * bindcol, int index, int offset);
      67             : 
      68             : static int rtrim(char *, int);
      69             : static int rtrim_u16(uint16_t * str, int len, uint16_t space);
      70             : static STATUS _bcp_read_hostfile(DBPROCESS * dbproc, TDSFILESTREAM * hostfile, bool *row_error, bool skip);
      71             : static int _bcp_readfmt_colinfo(DBPROCESS * dbproc, char *buf, BCP_HOSTCOLINFO * ci);
      72             : static int _bcp_get_term_var(const BYTE * pdata, const BYTE * term, int term_len);
      73             : static int _bcp_strftime(char *buf, size_t maxsize, const char *format, const TDSDATEREC * dr, int prec);
      74             : 
      75             : /*
      76             :  * "If a host file is being used ... the default data formats are as follows:
      77             :  *
      78             :  *  > The order, type, length and number of the columns in the host file are 
      79             :  *    assumed to be identical to the order, type and number of the columns in the database table.
      80             :  *  > If a given database column's data is fixed-length, 
      81             :  *    then the host file's  data column will also be fixed-length. 
      82             :  *  > If a given database column's data is variable-length or may contain null values, 
      83             :  *    the host file's data column will be prefixed by 
      84             :  *      a 4-byte length value for SYBTEXT and SYBIMAGE data types, and 
      85             :  *      a 1-byte length value for all other types.
      86             :  *  > There are no terminators of any kind between host file columns."
      87             :  */
      88             : 
      89             : static void
      90         402 : init_hostfile_columns(DBPROCESS *dbproc)
      91             : {
      92         402 :         const int ncols = dbproc->bcpinfo->bindinfo->num_cols;
      93             :         RETCODE erc;
      94             :         int icol;
      95             :         
      96         402 :         if (ncols == 0)
      97             :                 return;
      98             :                 
      99         402 :         if ((erc = bcp_columns(dbproc, ncols)) != SUCCEED) {
     100           0 :                 assert(erc == SUCCEED);
     101             :                 return;
     102             :         }
     103             :                 
     104        2428 :         for (icol = 0; icol < ncols; icol++) {
     105        2026 :                 const TDSCOLUMN *pcol = dbproc->bcpinfo->bindinfo->columns[icol];
     106        2026 :                 int prefixlen = 0, termlen = 0;
     107             :                 
     108        2026 :                 switch (pcol->column_type) {
     109             :                 case SYBTEXT:
     110             :                 case SYBIMAGE:
     111             :                         prefixlen = 4;
     112             :                         break;
     113        1886 :                 default:
     114        1886 :                         prefixlen = dbvarylen(dbproc, icol+1)? 1 : 0;
     115             :                 }
     116             :                 
     117        2026 :                 erc = bcp_colfmt(dbproc, icol+1, pcol->column_type, prefixlen, pcol->column_size, NULL, termlen, icol+1);
     118             :                 
     119        2026 :                 assert(erc == SUCCEED);
     120             :                 if (erc != SUCCEED)
     121             :                         return;
     122             :         }
     123             : }
     124             : 
     125             : 
     126             : /** 
     127             :  * \ingroup dblib_bcp
     128             :  * \brief Prepare for bulk copy operation on a table
     129             :  *
     130             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
     131             :  * \param tblname the name of the table receiving or providing the data.
     132             :  * \param hfile the data file opposite the table, if any.  
     133             :  * \param errfile the "error file" captures messages and, if errors are encountered, 
     134             :  *      copies of any rows that could not be written to the table.
     135             :  * \param direction one of 
     136             :  *              - \b DB_IN writing to the table
     137             :  *              - \b DB_OUT writing to the host file
     138             :  *              .
     139             :  * \remarks bcp_init() sets the host file data format and acquires the table metadata.
     140             :  *      It is called before the other bulk copy functions. 
     141             :  *
     142             :  *      When writing to a table, bcp can use as its data source a data file (\a hfile), 
     143             :  *      or program data in an application's variables.  In the latter case, call bcp_bind() 
     144             :  *      to associate your data with the appropriate table column.  
     145             :  * \return SUCCEED or FAIL.
     146             :  * \sa  BCP_SETL(), bcp_bind(), bcp_done(), bcp_exec()
     147             :  */
     148             : RETCODE
     149         440 : bcp_init(DBPROCESS * dbproc, const char *tblname, const char *hfile, const char *errfile, int direction)
     150             : {
     151         440 :         tdsdump_log(TDS_DBG_FUNC, "bcp_init(%p, %s, %s, %s, %d)\n", 
     152             :                         dbproc, tblname? tblname:"NULL", hfile? hfile:"NULL", errfile? errfile:"NULL", direction);
     153         440 :         CHECK_CONN(FAIL);
     154             : 
     155             :         /* 
     156             :          * Validate other parameters 
     157             :          */
     158         440 :         if (dbproc->tds_socket->conn->tds_version < 0x500) {
     159           0 :                 dbperror(dbproc, SYBETDSVER, 0);
     160           0 :                 return FAIL;
     161             :         }
     162             : 
     163         440 :         if (tblname == NULL) {
     164           0 :                 dbperror(dbproc, SYBEBCITBNM, 0);
     165           0 :                 return FAIL;
     166             :         }
     167             : 
     168         514 :         if (direction != DB_QUERYOUT && !IS_TDS7_PLUS(dbproc->tds_socket->conn) &&
     169          74 :             strlen(tblname) > 92) {  /* 30.30.30 for Sybase */
     170           0 :                 dbperror(dbproc, SYBEBCITBLEN, 0);
     171           0 :                 return FAIL;
     172             :         }
     173             : 
     174         440 :         if (direction != DB_IN && direction != DB_OUT && direction != DB_QUERYOUT) {
     175           0 :                 dbperror(dbproc, SYBEBDIO, 0);
     176           0 :                 return FAIL;
     177             :         }
     178             : 
     179             :         /* Free previously allocated storage in dbproc & initialise flags, etc. */
     180         440 :         _bcp_free_storage(dbproc);
     181             : 
     182             :         /* Allocate storage */
     183         440 :         dbproc->bcpinfo = tds_alloc_bcpinfo();
     184         440 :         if (dbproc->bcpinfo == NULL)
     185             :                 goto memory_error;
     186             : 
     187         440 :         if (!tds_dstr_copy(&dbproc->bcpinfo->tablename, tblname))
     188             :                 goto memory_error;
     189             : 
     190         440 :         dbproc->bcpinfo->direction = direction;
     191             : 
     192         440 :         dbproc->bcpinfo->xfer_init = false;
     193         440 :         dbproc->bcpinfo->bind_count = 0;
     194             : 
     195         440 :         if (TDS_FAILED(tds_bcp_init(dbproc->tds_socket, dbproc->bcpinfo))) {
     196             :                 /* TODO return proper error */
     197             :                 /* Attempt to use Bulk Copy with a non-existent Server table (might be why ...) */
     198           0 :                 dbperror(dbproc, SYBEBCNT, 0);
     199           0 :                 return FAIL;
     200             :         }
     201             : 
     202             :         /* Prepare default hostfile columns */
     203             :         
     204         440 :         if (hfile == NULL) {
     205          38 :                 dbproc->hostfileinfo = NULL;
     206          38 :                 return SUCCEED;
     207             :         }
     208             : 
     209         402 :         dbproc->hostfileinfo = tds_new0(BCP_HOSTFILEINFO, 1);
     210             : 
     211         402 :         if (dbproc->hostfileinfo == NULL)
     212             :                 goto memory_error;
     213         402 :         dbproc->hostfileinfo->maxerrs = 10;
     214         402 :         dbproc->hostfileinfo->firstrow = 1;
     215         402 :         if ((dbproc->hostfileinfo->hostfile = strdup(hfile)) == NULL)
     216             :                 goto memory_error;
     217             : 
     218         402 :         if (errfile != NULL)
     219         402 :                 if ((dbproc->hostfileinfo->errorfile = strdup(errfile)) == NULL)
     220             :                         goto memory_error;
     221             : 
     222         402 :         init_hostfile_columns(dbproc);
     223             : 
     224         402 :         return SUCCEED;
     225             : 
     226           0 : memory_error:
     227           0 :         _bcp_free_storage(dbproc);
     228           0 :         dbperror(dbproc, SYBEMEM, ENOMEM);
     229           0 :         return FAIL;
     230             : }
     231             : 
     232             : 
     233             : /** 
     234             :  * \ingroup dblib_bcp
     235             :  * \brief Set the length of a host variable to be written to a table.
     236             :  * 
     237             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
     238             :  * \param varlen size of the variable, in bytes, or
     239             :  *      - \b 0 indicating NULL
     240             :  *      - \b -1 indicating size is determined by the prefix or terminator.  
     241             :  *              (If both a prefix and a terminator are present, bcp is supposed to use the smaller of the 
     242             :  *               two.  This feature might or might not actually work.)
     243             :  * \param table_column the number of the column in the table (starting with 1, not zero).
     244             :  * 
     245             :  * \return SUCCEED or FAIL.
     246             :  * \sa  bcp_bind(), bcp_colptr(), bcp_sendrow() 
     247             :  */
     248             : RETCODE
     249         130 : bcp_collen(DBPROCESS * dbproc, DBINT varlen, int table_column)
     250             : {
     251             :         TDSCOLUMN *bcpcol;
     252             : 
     253         130 :         tdsdump_log(TDS_DBG_FUNC, "bcp_collen(%p, %d, %d)\n", dbproc, varlen, table_column);
     254             :         
     255         130 :         CHECK_CONN(FAIL);
     256         130 :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);            /* not initialized */
     257         130 :         DBPERROR_RETURN(dbproc->bcpinfo->direction != DB_IN, SYBEBCPN)    /* not inbound */
     258         130 :         DBPERROR_RETURN(dbproc->hostfileinfo != NULL, SYBEBCPI)              /* cannot have data file */
     259         130 :         CHECK_PARAMETER(0 < table_column && 
     260             :                             table_column <= dbproc->bcpinfo->bindinfo->num_cols, SYBECNOR, FAIL);
     261             :         
     262         130 :         bcpcol = dbproc->bcpinfo->bindinfo->columns[table_column - 1];
     263             : 
     264             :         /* Sybase library does not check for NULL here, only sending, so don't
     265             :          * check and send SYBEBCNN */
     266         130 :         bcpcol->column_bindlen = varlen;
     267             : 
     268         130 :         return SUCCEED;
     269             : }
     270             : 
     271             : /** 
     272             :  * \ingroup dblib_bcp
     273             :  * \brief Indicate how many columns are to be found in the datafile.
     274             :  * 
     275             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
     276             :  * \param host_colcount count of columns in the datafile, irrespective of how many you intend to use. 
     277             :  * \remarks This function describes the file as it is, not how it will be used.  
     278             :  * 
     279             :  * \return SUCCEED or FAIL.  It's hard to see how it could fail.  
     280             :  * \sa  bcp_colfmt()    
     281             :  */
     282             : RETCODE
     283         794 : bcp_columns(DBPROCESS * dbproc, int host_colcount)
     284             : {
     285             :         int i;
     286             : 
     287         794 :         tdsdump_log(TDS_DBG_FUNC, "bcp_columns(%p, %d)\n", dbproc, host_colcount);
     288         794 :         CHECK_CONN(FAIL);
     289         794 :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
     290         794 :         CHECK_PARAMETER(dbproc->hostfileinfo, SYBEBIVI, FAIL);
     291             : 
     292         794 :         if (host_colcount < 1) {
     293           0 :                 dbperror(dbproc, SYBEBCFO, 0);
     294           0 :                 return FAIL;
     295             :         }
     296             : 
     297         794 :         _bcp_free_columns(dbproc);
     298             : 
     299         794 :         dbproc->hostfileinfo->host_columns = tds_new0(BCP_HOSTCOLINFO *, host_colcount);
     300         794 :         if (dbproc->hostfileinfo->host_columns == NULL) {
     301           0 :                 dbperror(dbproc, SYBEMEM, ENOMEM);
     302           0 :                 return FAIL;
     303             :         }
     304             : 
     305         794 :         dbproc->hostfileinfo->host_colcount = host_colcount;
     306             : 
     307        4832 :         for (i = 0; i < host_colcount; i++) {
     308        4038 :                 dbproc->hostfileinfo->host_columns[i] = tds_new0(BCP_HOSTCOLINFO, 1);
     309        4038 :                 if (dbproc->hostfileinfo->host_columns[i] == NULL) {
     310           0 :                         dbproc->hostfileinfo->host_colcount = i;
     311           0 :                         _bcp_free_columns(dbproc);
     312           0 :                         dbperror(dbproc, SYBEMEM, ENOMEM);
     313           0 :                         return FAIL;
     314             :                 }
     315             :         }
     316             : 
     317             :         return SUCCEED;
     318             : }
     319             : 
     320             : /** 
     321             :  * \ingroup dblib_bcp
     322             :  * \brief Specify the format of a datafile prior to writing to a table.
     323             :  * 
     324             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
     325             :  * \param host_colnum datafile column number (starting with 1, not zero).
     326             :  * \param host_type dataype token describing the data type in \a host_colnum.  E.g. SYBCHAR for character data.
     327             :  * \param host_prefixlen size of the prefix in the datafile column, if any.  For delimited files: zero.  
     328             :  *                      May be 0, 1, 2, or 4 bytes.  The prefix will be read as an integer (not a character string) from the 
     329             :  *                      data file, and will be interpreted the data size of that column, in bytes.  
     330             :  *                      The value -1 means to use the default recommended prefix size for the datatype.
     331             :  * \param host_collen maximum size of datafile column exclusive of any prefix/terminator.  Just the data, ma'am.
     332             :  *              Special values:
     333             :  *                      - \b  0 indicates a null value for a variable-length field with no prefix/terminator.
     334             :  *                      - \b -1 for fixed-length non-null datatypes
     335             :  *                      - \b -1 for variable-length datatypes (e.g. SYBCHAR) where the length is established 
     336             :  *                              by a prefix/terminator.  
     337             :  * \param host_term the sequence of characters that will serve as a column terminator (delimiter) in the datafile.  
     338             :  *                      Often a tab character, but can be any string of any length.  Zero indicates no terminator.  
     339             :  *                      Special characters:
     340             :  *                              - \b '\\0' terminator is an ASCII NUL.
     341             :  *                              - \b '\\t' terminator is an ASCII TAB.
     342             :  *                              - \b '\\n' terminator is an ASCII NL.
     343             :  * \param host_termlen the length of \a host_term, in bytes. 
     344             :  * \param table_colnum Nth column, starting at 1, in the table that maps to \a host_colnum.  
     345             :  *      If there is a column in the datafile that does not map to a table column, set \a table_colnum to zero.  
     346             :  *
     347             :  *\remarks  bcp_colfmt() is called once for each column in the datafile, as specified with bcp_columns().  
     348             :  * In so doing, you describe to FreeTDS how to parse each line of your datafile, and where to send each field.  
     349             :  *
     350             :  * When a prefix or terminator is used with variable-length data, \a host_collen may have one of three values:
     351             :  *              - \b positive indicating the maximum number of bytes to be used
     352             :  *              - \b 0 indicating NULL
     353             :  *              - \b -1 indicating no maximum; all data, as described by the prefix/terminator will be used.  
     354             :  *              .
     355             :  * \return SUCCEED or FAIL.
     356             :  * \sa  bcp_batch(), bcp_bind(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(),
     357             :  *      bcp_control(), bcp_done(), bcp_exec(), bcp_init(), bcp_sendrow
     358             :  */
     359             : RETCODE
     360        4048 : bcp_colfmt(DBPROCESS * dbproc, int host_colnum, int host_type, int host_prefixlen, DBINT host_collen, const BYTE * host_term,
     361             :            int host_termlen, int table_colnum)
     362             : {
     363             :         BCP_HOSTCOLINFO *hostcol;
     364        4048 :         BYTE *terminator = NULL;
     365             : 
     366        4048 :         tdsdump_log(TDS_DBG_FUNC, "bcp_colfmt(%p, %d, %d, %d, %d, %p, %d, %d)\n", 
     367             :                     dbproc, host_colnum, host_type, host_prefixlen, (int) host_collen, host_term, host_termlen, table_colnum);
     368        4048 :         CHECK_CONN(FAIL);
     369        4048 :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
     370        4048 :         CHECK_PARAMETER(dbproc->hostfileinfo, SYBEBIVI, FAIL);
     371             : 
     372             :         /* Microsoft specifies a "file_termlen" of zero if there's no terminator */
     373        4048 :         if (dbproc->msdblib && host_termlen == 0)
     374             :                 host_termlen = -1;
     375             : 
     376        4048 :         if (host_termlen < 0)
     377           0 :                 host_termlen = -1;
     378             : 
     379        4048 :         if (dbproc->hostfileinfo->host_colcount == 0) {
     380           0 :                 dbperror(dbproc, SYBEBCBC, 0);
     381           0 :                 return FAIL;
     382             :         }
     383             : 
     384        4048 :         if (host_colnum < 1) {
     385           0 :                 dbperror(dbproc, SYBEBCFO, 0);
     386           0 :                 return FAIL;
     387             :         }
     388             : 
     389        4048 :         if (host_colnum > dbproc->hostfileinfo->host_colcount) {
     390           0 :                 dbperror(dbproc, SYBECNOR, 0);
     391           0 :                 return FAIL;
     392             :         }
     393             : 
     394             :         /* Note: MS bcp supports 1, 2, 4, and 8; but not 3; but returns SYBEVDPT on error.
     395             :          * -1 is a special value that will be resolved after database connection. */
     396        4048 :         if (host_prefixlen != 0 && host_prefixlen != 1 && host_prefixlen != 2 && host_prefixlen != 4 && host_prefixlen != -1) {
     397           0 :                 dbperror(dbproc, SYBEBCPREF, 0);
     398           0 :                 return FAIL;
     399             :         }
     400             : 
     401             :         /* if column is not copied you cannot specify destination type */
     402        4048 :         if (table_colnum <= 0 && host_type == 0) {
     403           0 :                 dbperror(dbproc, SYBEBCPCTYP, 0);
     404           0 :                 return FAIL;
     405             :         }
     406             : 
     407        8096 :         if (table_colnum > 0 && !is_tds_type_valid(host_type)) {
     408           0 :                 dbperror(dbproc, SYBEUDTY, 0);
     409           0 :                 return FAIL;
     410             :         }
     411             : 
     412        4048 :         if (host_collen < -1) {
     413           0 :                 dbperror(dbproc, SYBEBCHLEN, 0);
     414           0 :                 return FAIL;
     415             :         }
     416             : 
     417             :         /* No official error message.  Fix and warn. */
     418        4048 :         if (is_fixed_type(host_type) && (host_collen != -1 && host_collen != 0)) {
     419         834 :                 tdsdump_log(TDS_DBG_FUNC,
     420             :                             "bcp_colfmt: changing host_collen to -1 from %d for fixed type %d.\n", 
     421             :                             host_collen, host_type);
     422             :                 host_collen = -1;
     423             :         }
     424             : 
     425             :         /* 
     426             :          * If there's a positive terminator length, we need a valid terminator pointer.
     427             :          * If the terminator length is 0 or -1, then there's no terminator.
     428             :          */
     429        4048 :         if (host_term == NULL && host_termlen > 0) {
     430           0 :                 dbperror(dbproc, SYBEVDPT, 0);  /* "all variable-length data must have either a length-prefix ..." */
     431           0 :                 return FAIL;
     432             :         }
     433             : 
     434             :         /* Does not make sense to have a prefix and a terminator. */
     435        4048 :         if (host_prefixlen != 0 && host_termlen > 0) {
     436           0 :                 tdsdump_log(TDS_DBG_FUNC, "bcp_colfmt: host column %d has a prefix and a terminator.\n", host_colnum);
     437           0 :                 dbperror(dbproc, SYBEVDPT, 0);
     438           0 :                 return FAIL;
     439             :         }
     440             : 
     441        4048 :         hostcol = dbproc->hostfileinfo->host_columns[host_colnum - 1];
     442             : 
     443             :         /* TODO add precision scale and join with bcp_colfmt_ps */
     444        4048 :         if (host_term && host_termlen > 0) {
     445        1902 :                 if ((terminator = tds_new(BYTE, host_termlen)) == NULL) {
     446           0 :                         dbperror(dbproc, SYBEMEM, errno);
     447           0 :                         return FAIL;
     448             :                 }
     449        1902 :                 memcpy(terminator, host_term, host_termlen);
     450             :         }
     451        4048 :         hostcol->host_column = host_colnum;
     452        4048 :         hostcol->datatype = host_type ? (TDS_SERVER_TYPE) host_type : TDS_INVALID_TYPE;
     453        4048 :         hostcol->prefix_len = host_prefixlen;
     454        4048 :         hostcol->column_len = host_collen;
     455        4048 :         free(hostcol->terminator);
     456        4048 :         hostcol->terminator = terminator;
     457        4048 :         hostcol->term_len = host_termlen;
     458        4048 :         hostcol->tab_colnum = table_colnum;
     459             : 
     460        4048 :         return SUCCEED;
     461             : }
     462             : 
     463             : /** 
     464             :  * \ingroup dblib_bcp
     465             :  * \brief Specify the format of a host file for bulk copy purposes, 
     466             :  *      with precision and scale support for numeric and decimal columns.
     467             :  * 
     468             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
     469             :  * \param host_colnum datafile column number (starting with 1, not zero).
     470             :  * \param host_type dataype token describing the data type in \a host_colnum.  E.g. SYBCHAR for character data.
     471             :  * \param host_prefixlen size of the prefix in the datafile column, if any.  For delimited files: zero.  
     472             :  *                      May be 0, 1, 2, or 4 bytes.  The prefix will be read as an integer (not a character string) from the 
     473             :  *                      data file, and will be interpreted the data size of that column, in bytes.  
     474             :  * \param host_collen maximum size of datafile column, exclusive of any prefix/terminator.  Just the data, ma'am.  
     475             :  *              Special values:
     476             :  *                      - \b 0 indicates NULL.  
     477             :  *                      - \b -1 for fixed-length non-null datatypes
     478             :  *                      - \b -1 for variable-length datatypes (e.g. SYBCHAR) where the length is established 
     479             :  *                              by a prefix/terminator.  
     480             :  * \param host_term the sequence of characters that will serve as a column terminator (delimiter) in the datafile.  
     481             :  *                      Often a tab character, but can be any string of any length.  Zero indicates no terminator.  
     482             :  *                      Special characters:
     483             :  *                              - \b '\\0' terminator is an ASCII NUL.
     484             :  *                              - \b '\\t' terminator is an ASCII TAB.
     485             :  *                              - \b '\\n' terminator is an ASCII NL.
     486             :  * \param host_termlen the length of \a host_term, in bytes. 
     487             :  * \param table_colnum Nth column, starting at 1, in the table that maps to \a host_colnum.  
     488             :  *      If there is a column in the datafile that does not map to a table column, set \a table_colnum to zero.  
     489             :  * \param typeinfo something
     490             :  * \todo Not implemented.
     491             :  * \return SUCCEED or FAIL.
     492             :  * \sa  bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(),
     493             :  *      bcp_control(), bcp_done(), bcp_exec(), bcp_init(), bcp_sendrow
     494             :  */
     495             : RETCODE
     496           0 : bcp_colfmt_ps(DBPROCESS * dbproc, int host_colnum, int host_type,
     497             :               int host_prefixlen, DBINT host_collen, BYTE * host_term, int host_termlen, int table_colnum, DBTYPEINFO * typeinfo)
     498             : {
     499           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED: bcp_colfmt_ps(%p, %d, %d, %d, %d, %p, %d, %d, %p)\n",
     500             :                     dbproc, host_colnum, host_type, host_prefixlen, (int) host_collen,
     501             :                     host_term, host_termlen, table_colnum, typeinfo);
     502           0 :         CHECK_CONN(FAIL);
     503           0 :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
     504             :         
     505             :         /* dbperror(dbproc, , 0);        Illegal precision specified */
     506             : 
     507             :         /* TODO see bcp_colfmt */
     508             :         return FAIL;
     509             : }
     510             : 
     511             : 
     512             : /** 
     513             :  * \ingroup dblib_bcp
     514             :  * \brief Set BCP options for uploading a datafile
     515             :  * 
     516             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
     517             :  * \param field symbolic constant indicating the option to be set, one of:
     518             :  *              - \b BCPMAXERRS Maximum errors tolerated before quitting. The default is 10.
     519             :  *              - \b BCPFIRST The first row to read in the datafile. The default is 1. 
     520             :  *              - \b BCPLAST The last row to read in the datafile. The default is to copy all rows. A value of
     521             :  *                      -1 resets this field to its default?
     522             :  *              - \b BCPBATCH The number of rows per batch.  Default is 0, meaning a single batch. 
     523             :  * \param value The value for \a field.
     524             :  *
     525             :  * \remarks These options control the behavior of bcp_exec().  
     526             :  * When writing to a table from application host memory variables, 
     527             :  * program logic controls error tolerance and batch size. 
     528             :  * 
     529             :  * \return SUCCEED or FAIL.
     530             :  * \sa  bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_done(), bcp_exec(), bcp_options()
     531             :  */
     532             : RETCODE
     533          50 : bcp_control(DBPROCESS * dbproc, int field, DBINT value)
     534             : {
     535          50 :         tdsdump_log(TDS_DBG_FUNC, "bcp_control(%p, %d, %d)\n", dbproc, field, value);
     536          50 :         CHECK_CONN(FAIL);
     537          50 :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
     538             : 
     539          50 :         if (field == BCPKEEPIDENTITY) {
     540           0 :                 dbproc->bcpinfo->identity_insert_on = (value != 0);
     541           0 :                 return SUCCEED;
     542             :         }
     543             : 
     544          50 :         CHECK_PARAMETER(dbproc->hostfileinfo, SYBEBIVI, FAIL);
     545             : 
     546          50 :         switch (field) {
     547             : 
     548          10 :         case BCPMAXERRS:
     549          10 :                 if (value < 1)
     550           0 :                         value = 10;
     551          10 :                 dbproc->hostfileinfo->maxerrs = value;
     552          10 :                 break;
     553          10 :         case BCPFIRST:
     554          10 :                 if (value < 1)
     555          10 :                         value = 1;
     556          10 :                 dbproc->hostfileinfo->firstrow = value;
     557          10 :                 break;
     558          10 :         case BCPLAST:
     559          10 :                 dbproc->hostfileinfo->lastrow = value;
     560          10 :                 break;
     561          10 :         case BCPBATCH:
     562          10 :                 dbproc->hostfileinfo->batch = value;
     563          10 :                 break;
     564          10 :         case BCPDRYRUN:
     565          10 :                 dbproc->bcpinfo->dry_run = value;
     566          10 :                 break;
     567             : 
     568           0 :         default:
     569           0 :                 dbperror(dbproc, SYBEIFNB, 0);
     570           0 :                 return FAIL;
     571             :         }
     572             :         return SUCCEED;
     573             : }
     574             : 
     575             : /*
     576             :  * \ingroup dblib_bcp
     577             :  * \brief Get BCP batch option
     578             :  *
     579             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
     580             :  * \remarks This function is specific to FreeTDS.
     581             :  *
     582             :  * \return the value that was set by bcp_control.
     583             :  * \sa  bcp_batch(), bcp_control()
     584             :  */
     585             : int
     586           0 : bcp_getbatchsize(DBPROCESS * dbproc)
     587             : {
     588           0 :         CHECK_CONN(-1);
     589           0 :         CHECK_PARAMETER(dbproc->hostfileinfo, SYBEBCPI, -1);
     590           0 :         return dbproc->hostfileinfo->batch;
     591             : }
     592             : 
     593             : /*
     594             :  * \ingroup dblib_bcp
     595             :  * \brief Get number of columns in the BCP data file
     596             :  *
     597             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
     598             :  * \remarks This function is specific to FreeTDS.
     599             :  *
     600             :  * \return the value that was set by bcp_columns(). This represents the number
     601             :  *     of columns of data in the saved data file. Usually the same as the number
     602             :  *     of columns in the database table, but could be fewer if a Format File is
     603             :  *     in use which only selects a subset of the table columns.
     604             :  *
     605             :  * \sa bcp_columns()
     606             :  */
     607             : int
     608          10 : bcp_gethostcolcount(DBPROCESS *dbproc)
     609             : {
     610          10 :         CHECK_CONN(-1);
     611          10 :         CHECK_PARAMETER(dbproc->hostfileinfo, SYBEBCPI, -1);
     612          10 :         return dbproc->hostfileinfo->host_colcount;
     613             : }
     614             : 
     615             : /** 
     616             :  * \ingroup dblib_bcp
     617             :  * \brief Set bulk copy options.
     618             :  * 
     619             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
     620             :  * \param option symbolic constant indicating the option to be set, one of:
     621             :  *              - \b BCPLABELED Not implemented.
     622             :  *              - \b BCPHINTS The hint to be passed when the bulk-copy begins.  
     623             :  * \param value The string constant for \a option a/k/a the hint.  One of:
     624             :  *              - \b ORDER The data are ordered in accordance with the table's clustered index.
     625             :  *              - \b ROWS_PER_BATCH The batch size
     626             :  *              - \b KILOBYTES_PER_BATCH The approximate number of kilobytes to use for a batch size
     627             :  *              - \b TABLOCK Lock the table
     628             :  *              - \b CHECK_CONSTRAINTS Apply constraints
     629             :  *              - \b FIRE_TRIGGERS Fire any INSERT triggers on the target table
     630             :  * \param valuelen The length of \a value. Ignored for fixed-length option types.
     631             :  * 
     632             :  * \return SUCCEED or FAIL.
     633             :  * \sa  bcp_control(), 
     634             :  *      bcp_exec(), 
     635             :  * \todo Simplify.
     636             :  */
     637             : RETCODE
     638          12 : bcp_options(DBPROCESS *dbproc, int option, BYTE *value, int valuelen)
     639             : {
     640          12 :         tdsdump_log(TDS_DBG_FUNC, "bcp_options(%p, %d, %p, %d)\n", dbproc, option, value, valuelen);
     641          12 :         CHECK_CONN(FAIL);
     642          12 :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
     643          12 :         CHECK_NULP(value, "bcp_options", 3, FAIL);
     644             : 
     645          12 :         switch (option) {
     646           0 :         case BCPLABELED:
     647           0 :                 tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED bcp option: BCPLABELED\n");
     648             :                 break;
     649          12 :         case BCPHINTS:
     650          12 :                 if (!value || valuelen <= 0)
     651             :                         break;
     652             : 
     653             :                 /* Hint documentation: https://learn.microsoft.com/en-us/sql/t-sql/statements/bulk-insert-transact-sql */
     654          12 :                 if (tds_dstr_copyn(&dbproc->bcpinfo->hint, (char *) value, valuelen))
     655             :                         return SUCCEED;
     656             :                 break;
     657             : 
     658           0 :         default:
     659           0 :                 tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED bcp option: %u\n", option);
     660             :                 break;
     661             :         }
     662           0 :         return FAIL;
     663             : }
     664             : 
     665             : /** 
     666             :  * \ingroup dblib_bcp
     667             :  * \brief Override bcp_bind() by pointing to a different host variable.
     668             :  * 
     669             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
     670             :  * \param colptr The pointer, the address of your variable. 
     671             :  * \param table_column The 1-based column ordinal in the table.  
     672             :  * \remarks Use between calls to bcp_sendrow().  After calling bcp_colptr(), 
     673             :  *              subsequent calls to bcp_sendrow() will bind to the new address.  
     674             :  * \return SUCCEED or FAIL.
     675             :  * \sa  bcp_bind(), bcp_collen(), bcp_sendrow() 
     676             :  */
     677             : RETCODE
     678           0 : bcp_colptr(DBPROCESS * dbproc, BYTE * colptr, int table_column)
     679             : {
     680             :         TDSCOLUMN *curcol;
     681             : 
     682           0 :         tdsdump_log(TDS_DBG_FUNC, "bcp_colptr(%p, %p, %d)\n", dbproc, colptr, table_column);
     683           0 :         CHECK_CONN(FAIL);
     684           0 :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
     685           0 :         CHECK_PARAMETER(dbproc->bcpinfo->bindinfo, SYBEBCPI, FAIL);
     686             :         /* colptr can be NULL */
     687             : 
     688           0 :         if (dbproc->bcpinfo->direction != DB_IN) {
     689           0 :                 dbperror(dbproc, SYBEBCPN, 0);
     690           0 :                 return FAIL;
     691             :         }
     692           0 :         if (table_column <= 0 || table_column > dbproc->bcpinfo->bindinfo->num_cols) {
     693           0 :                 dbperror(dbproc, SYBEBCPN, 0);
     694           0 :                 return FAIL;
     695             :         }
     696             :         
     697           0 :         curcol = dbproc->bcpinfo->bindinfo->columns[table_column - 1];
     698           0 :         curcol->column_varaddr = (TDS_CHAR *)colptr;
     699             : 
     700           0 :         return SUCCEED;
     701             : }
     702             : 
     703             : 
     704             : /** 
     705             :  * \ingroup dblib_bcp
     706             :  * \brief See if BCP_SETL() was used to set the LOGINREC for BCP work.  
     707             :  * 
     708             :  * \param login Address of the LOGINREC variable to be passed to dbopen(). 
     709             :  * 
     710             :  * \return TRUE or FALSE.
     711             :  * \sa  BCP_SETL(), bcp_init(), dblogin(), dbopen()
     712             :  */
     713             : DBBOOL
     714          10 : bcp_getl(LOGINREC * login)
     715             : {
     716          10 :         TDSLOGIN *tdsl = login->tds_login;
     717             : 
     718          10 :         tdsdump_log(TDS_DBG_FUNC, "bcp_getl(%p)\n", login);
     719             : 
     720          10 :         return (tdsl->bulk_copy);
     721             : }
     722             : 
     723             : /**
     724             :  * Convert column for output (usually to a file)
     725             :  * Conversion is slightly different from input as:
     726             :  * - date is formatted differently;
     727             :  * - you have to set properly numeric while on input the column metadata are
     728             :  *   used;
     729             :  * - we need to make sure buffer is always at least a minimum bytes.
     730             :  */
     731             : static int
     732        1926 : _bcp_convert_out(DBPROCESS * dbproc, TDSCOLUMN *curcol, BCP_HOSTCOLINFO *hostcol, TDS_UCHAR **p_data, const char *bcpdatefmt)
     733             : {
     734             :         BYTE *src;
     735             :         int srclen;
     736             :         int buflen;
     737        1926 :         int srctype = tds_get_conversion_type(curcol->column_type, curcol->column_size);
     738             : 
     739        1926 :         src = curcol->column_data;
     740        1926 :         if (is_blob_col(curcol))
     741         122 :                 src = (BYTE *) ((TDSBLOB *) src)->textvalue;
     742             : 
     743        1926 :         srclen = curcol->column_cur_size;
     744             : 
     745             :         /*
     746             :          * if we are converting datetime to string, need to override any
     747             :          * date time formats already established
     748             :          */
     749        1926 :         if (is_datetime_type(srctype) && is_ascii_type(hostcol->datatype)) {
     750             :                 TDSDATEREC when;
     751             : 
     752             :                 /* Some date/time types have variable precision (e.g. MS datetime2),
     753             :                  * and set curcol->column_prec with that precision.
     754             :                  * DATETIME is printed with precision 3 by MS BCP & ASE BCP however
     755             :                  * curcol->column_prec is not set for that type.
     756             :                  * (It might be better to set column_prec at load time for all
     757             :                  * of the datetime types...)
     758             :                  */
     759          80 :                 int prec = curcol->column_prec ? curcol->column_prec : 3;
     760             : 
     761          80 :                 tds_datecrack(srctype, src, &when);
     762          80 :                 buflen = _bcp_strftime((char *) *p_data, 256, bcpdatefmt, &when, prec);
     763        1846 :         } else if (srclen == 0 && is_variable_type(curcol->column_type)
     764          46 :                    && is_ascii_type(hostcol->datatype)) {
     765             :                 /*
     766             :                  * An empty string is denoted in the output file by a single ASCII NUL
     767             :                  * byte that we request by specifying a destination length of -1.  (Not
     768             :                  * to be confused with a database NULL, which is denoted in the output
     769             :                  * file with an empty string!)
     770             :                  */
     771          46 :                 (*p_data)[0] = 0;
     772          46 :                 buflen = 1;
     773        1800 :         } else if (is_numeric_type(hostcol->datatype)) {
     774           0 :                 TDS_NUMERIC *num = (TDS_NUMERIC *) (*p_data);
     775           0 :                 if (is_numeric_type(srctype)) {
     776           0 :                         TDS_NUMERIC *nsrc = (TDS_NUMERIC *) src;
     777           0 :                         num->precision = nsrc->precision;
     778           0 :                         num->scale = nsrc->scale;
     779             :                 } else {
     780           0 :                         num->precision = 18;
     781           0 :                         num->scale = 0;
     782             :                 }
     783           0 :                 buflen = tds_convert(dbproc->tds_socket->conn->tds_ctx, srctype, src, srclen, hostcol->datatype, (CONV_RESULT *) num);
     784           0 :                 if (buflen > 0)
     785           0 :                         buflen = tds_numeric_bytes_per_prec[num->precision] + 2;
     786        1800 :         } else if (!is_variable_type(hostcol->datatype)) {
     787          30 :                 buflen = tds_convert(dbproc->tds_socket->conn->tds_ctx, srctype, src, srclen, hostcol->datatype, (CONV_RESULT *) (*p_data));
     788             :         } else {
     789             :                 CONV_RESULT cr;
     790             : 
     791             :                 /*
     792             :                  * For null columns, the above work to determine the output buffer size is moot,
     793             :                  * because bcpcol->data_size is zero, so dbconvert() won't write anything,
     794             :                  * and returns zero.
     795             :                  */
     796        1770 :                 buflen = tds_convert(dbproc->tds_socket->conn->tds_ctx, srctype, src, srclen, hostcol->datatype, (CONV_RESULT *) &cr);
     797        1770 :                 if (buflen < 0)
     798           0 :                         return buflen;
     799             : 
     800        1770 :                 if (buflen >= 256) {
     801          30 :                         free(*p_data);
     802          30 :                         *p_data = (TDS_UCHAR *) cr.c;
     803             :                 } else {
     804        1740 :                         memcpy(*p_data, cr.c, buflen);
     805        1740 :                         free(cr.c);
     806             :                 }
     807             : 
     808             :                 /*
     809             :                  * Special case:  When outputting database varchar data
     810             :                  * (either varchar or nullable char) conversion may have
     811             :                  * trimmed trailing blanks such that nothing is left.
     812             :                  * In this case we need to put a single blank to the output file.
     813             :                  */
     814        1770 :                 if (is_char_type(curcol->column_type) && srclen > 0 && buflen == 0) {
     815           0 :                         strcpy ((char *) (*p_data), " ");
     816           0 :                         buflen = 1;
     817             :                 }
     818             :         }
     819             :         return buflen;
     820             : }
     821             : 
     822             : static int
     823             : bcp_cache_prefix_len(BCP_HOSTCOLINFO *hostcol, const TDSCOLUMN *curcol)
     824             : {
     825             :         int plen;
     826             : 
     827           0 :         if (type_has_textptr(hostcol->datatype))
     828             :                 plen = 4;
     829           0 :         else if (is_numeric_type(hostcol->datatype))
     830             :                 plen = 1;
     831           0 :         else if (!is_fixed_type(hostcol->datatype))
     832             :                 plen = 2;
     833           0 :         else if (curcol->column_nullable)
     834             :                 plen = 1;
     835             :         else
     836           0 :                 plen = 0;
     837             :         /* cache */
     838           0 :         return hostcol->prefix_len = plen;
     839             : }
     840             : 
     841             : static RETCODE
     842        2216 : bcp_write_prefix(TDSFILEOUTSTREAM *hoststream, BCP_HOSTCOLINFO *hostcol, TDSCOLUMN *curcol, int buflen)
     843             : {
     844             :         union {
     845             :                 TDS_TINYINT ti;
     846             :                 TDS_SMALLINT si;
     847             :                 TDS_INT li;
     848             :         } u;
     849             :         int plen;
     850             : 
     851             :         /* compute prefix len if needed */
     852        2216 :         if ((plen = hostcol->prefix_len) == -1)
     853           0 :                 plen = bcp_cache_prefix_len(hostcol, curcol);
     854             : 
     855             :         /* output prefix to file */
     856        2216 :         switch (plen) {
     857             :         default:
     858             :                 return SUCCEED;
     859          20 :         case 1:
     860          20 :                 u.ti = buflen;
     861          20 :                 break;
     862           0 :         case 2:
     863           0 :                 u.si = buflen;
     864           0 :                 break;
     865          10 :         case 4:
     866          10 :                 u.li = buflen;
     867          10 :                 break;
     868             :         }
     869          30 :         return TDS_SUCCEED(tds_fileout_stream_put(hoststream, &u, plen)) ? SUCCEED : FAIL;
     870             : }
     871             : 
     872             : /**
     873             :  * \ingroup dblib_bcp_internal
     874             :  * \brief
     875             :  *
     876             :  *
     877             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
     878             :  * \param rows_copied
     879             :  *
     880             :  * \return SUCCEED or FAIL.
     881             :  * \sa  BCP_SETL(), bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), bcp_done(), bcp_exec(), bcp_getl(), bcp_init(), bcp_moretext(), bcp_options(), bcp_readfmt(), bcp_sendrow()
     882             :  */
     883             : static RETCODE
     884         196 : _bcp_exec_out(DBPROCESS * dbproc, DBINT * rows_copied)
     885             : {
     886             :         TDSFILEOUTSTREAM hoststream;
     887         196 :         FILE *hostfp = NULL;
     888         196 :         TDS_UCHAR *data = NULL;
     889             :         int i;
     890             : 
     891             :         TDSSOCKET *tds;
     892             :         TDSRESULTINFO *resinfo;
     893         196 :         TDSCOLUMN *curcol = NULL;
     894             :         BCP_HOSTCOLINFO *hostcol;
     895             :         int buflen;
     896             : 
     897             :         TDS_INT result_type;
     898             : 
     899             :         TDS_INT row_of_query;
     900             :         DBINT rows_written;
     901             :         const char *bcpdatefmt;
     902             :         TDSRET tdsret;
     903             : 
     904         196 :         tdsdump_log(TDS_DBG_FUNC, "_bcp_exec_out(%p, %p)\n", dbproc, rows_copied);
     905         196 :         assert(dbproc);
     906         196 :         assert(rows_copied);
     907             : 
     908         196 :         tds = dbproc->tds_socket;
     909         196 :         assert(tds);
     910             : 
     911             :         /* See if they want a BCP date format different from the default.
     912             :          * The ASE bcp client does use the locale for bcp out; but all bcp clients
     913             :          * appear to successfully read this format for input, regardless of locale.
     914             :          */
     915         196 :         bcpdatefmt = getenv("FREEBCP_DATEFMT");
     916         196 :         if (bcpdatefmt && !strcmp(bcpdatefmt, BCP_DEFAULT_DATEFMT))
     917           0 :                 bcpdatefmt = NULL;
     918             : 
     919         196 :         if (dbproc->bcpinfo->direction == DB_QUERYOUT ) {
     920           0 :                 if (TDS_FAILED(tds_submit_query(tds, tds_dstr_cstr(&dbproc->bcpinfo->tablename))))
     921             :                         return FAIL;
     922             :         } else {
     923             :                 /* TODO quote if needed */
     924         392 :                 if (TDS_FAILED(tds_submit_queryf(tds, "select * from %s", tds_dstr_cstr(&dbproc->bcpinfo->tablename))))
     925             :                         return FAIL;
     926             :         }
     927             : 
     928         196 :         tdsret = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS);
     929         196 :         if (TDS_FAILED(tdsret))
     930             :                 return FAIL;
     931             : 
     932         196 :         if (!tds->res_info) {
     933             :                 /* TODO flush/cancel to keep consistent state */
     934             :                 return FAIL;
     935             :         }
     936             : 
     937         196 :         resinfo = tds->res_info;
     938             : 
     939         196 :         row_of_query = 0;
     940         196 :         rows_written = 0;
     941             : 
     942             :         /* allocate at least 256 bytes */
     943             :         /* allocate data for buffer conversion */
     944         196 :         data = tds_new(TDS_UCHAR, 256);
     945         196 :         if (!data) {
     946           0 :                 dbperror(dbproc, SYBEMEM, errno);
     947             :                 goto Cleanup;
     948             :         }
     949             : 
     950             :         /*
     951             :          * TODO above we allocate many buffer just to convert and store
     952             :          * to file.. avoid all that passages...
     953             :          */
     954         196 :         if (!(hostfp = fopen(dbproc->hostfileinfo->hostfile, "wb"))) {
     955           0 :                 dbperror(dbproc, SYBEBCUO, errno);
     956           0 :                 goto Cleanup;
     957             :         }
     958         196 :         tds_fileout_stream_init(&hoststream, hostfp, _IOFBF);
     959             : 
     960             :         /* fetch a row of data from the server */
     961             : 
     962         838 :         while (tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE)
     963             :                 == TDS_SUCCESS) {
     964             : 
     965         642 :                 if (result_type != TDS_ROW_RESULT && result_type != TDS_COMPUTE_RESULT)
     966             :                         break;
     967             : 
     968         446 :                 row_of_query++;
     969             : 
     970             :                 /* skip rows outside of the firstrow/lastrow range, if specified */
     971         446 :                 if (dbproc->hostfileinfo->firstrow > row_of_query)
     972           0 :                         continue;
     973         446 :                 if (dbproc->hostfileinfo->lastrow > 0 && row_of_query > dbproc->hostfileinfo->lastrow) {
     974             :                         /* TODO: If this is freebcp we could now just return success,
     975             :                          * rather than waste time processing the rest of data.
     976             :                          * In other cases we could perhaps send a cancel request.
     977             :                          */
     978           0 :                         continue;
     979             :                 }
     980             : 
     981             :                 /* Go through the hostfile columns, finding those that relate to database columns. */
     982        2216 :                 for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
     983        2216 :                         hostcol = dbproc->hostfileinfo->host_columns[i];
     984        2216 :                         if (hostcol->tab_colnum < 1 || hostcol->tab_colnum > resinfo->num_cols)
     985           0 :                                 continue;
     986             : 
     987        2216 :                         curcol = resinfo->columns[hostcol->tab_colnum - 1];
     988             : 
     989        2216 :                         if (curcol->column_cur_size < 0) {
     990             :                                 buflen = 0;
     991             :                         } else {
     992        1926 :                                 buflen = _bcp_convert_out(dbproc, curcol, hostcol, &data, bcpdatefmt);
     993             :                         }
     994        1926 :                         if (buflen < 0) {
     995           0 :                                 _dblib_convert_err(dbproc, buflen);
     996           0 :                                 goto Cleanup;
     997             :                         }
     998             : 
     999             :                         /* The prefix */
    1000        2216 :                         if (bcp_write_prefix(&hoststream, hostcol, curcol, buflen) != SUCCEED)
    1001             :                                 goto write_error;
    1002             : 
    1003             :                         /* The data */
    1004        2216 :                         if (hostcol->column_len != -1) {
    1005          40 :                                 buflen = TDS_MIN(buflen, hostcol->column_len);
    1006             :                         }
    1007             : 
    1008        2216 :                         if (buflen > 0) {
    1009        1926 :                                 if (!TDS_SUCCEED(tds_fileout_stream_put(&hoststream, data, buflen)))
    1010             :                                         goto write_error;
    1011             :                         }
    1012             : 
    1013             :                         /* The terminator */
    1014        2216 :                         if (hostcol->terminator && hostcol->term_len > 0) {
    1015        2156 :                                 if (!TDS_SUCCEED(tds_fileout_stream_put(&hoststream, hostcol->terminator, hostcol->term_len)))
    1016             :                                         goto write_error;
    1017             :                         }
    1018             :                 }
    1019         446 :                 rows_written++;
    1020             :         }
    1021             : 
    1022         196 :         if (TDS_FAILED(tds_fileout_stream_flush(&hoststream)) || fclose(hostfp) != 0) {
    1023           0 :                 dbperror(dbproc, SYBEBCUC, errno);
    1024           0 :                 goto Cleanup;
    1025             :         }
    1026         196 :         hostfp = NULL;
    1027             : 
    1028         196 :         if (row_of_query + 1 < dbproc->hostfileinfo->firstrow) {
    1029             :                 /*
    1030             :                  * The table which bulk-copy is attempting to
    1031             :                  * copy to a host-file is shorter than the
    1032             :                  * number of rows which bulk-copy was instructed to skip.
    1033             :                  */
    1034             :                 /* TODO reset TDSSOCKET state */
    1035           0 :                 dbperror(dbproc, SYBETTS, 0);
    1036             :                 goto Cleanup;
    1037             :         }
    1038             : 
    1039         196 :         *rows_copied = rows_written;
    1040         196 :         free(data);
    1041         196 :         return SUCCEED;
    1042             : 
    1043           0 : write_error:
    1044           0 :         dbperror(dbproc, SYBEBCWE, errno);
    1045             : 
    1046           0 : Cleanup:
    1047           0 :         if (hostfp)
    1048           0 :                 fclose(hostfp);
    1049           0 :         free(data);
    1050           0 :         return FAIL;
    1051             : }
    1052             : 
    1053             : static STATUS
    1054         206 : _bcp_check_eof(DBPROCESS * dbproc, TDSFILESTREAM* stream, int icol)
    1055             : {
    1056         206 :         int errnum = errno;
    1057             :         FILE *file;
    1058             : 
    1059         206 :         tdsdump_log(TDS_DBG_FUNC, "_bcp_check_eof(%p, %p, %d)\n", dbproc, stream, icol);
    1060         206 :         assert(dbproc);
    1061         206 :         assert(stream);
    1062             : 
    1063         206 :         file = stream->f;
    1064         206 :         assert(file);
    1065             : 
    1066         206 :         if (stream->inpos == stream->inlen && feof(file)) {
    1067         206 :                 if (icol == 0) {
    1068         206 :                         tdsdump_log(TDS_DBG_FUNC, "Normal end-of-file reached while loading bcp data file.\n");
    1069             :                         return NO_MORE_ROWS;
    1070             :                 }
    1071           0 :                 dbperror(dbproc, SYBEBEOF, errnum);
    1072           0 :                 return FAIL;
    1073             :         } 
    1074           0 :         dbperror(dbproc, SYBEBCRE, errnum);
    1075           0 :         return FAIL;
    1076             : }
    1077             : 
    1078             : /**
    1079             :  * Convert column for input to a table
    1080             :  */
    1081             : static TDSRET
    1082        4708 : _bcp_convert_in(DBPROCESS *dbproc, TDS_SERVER_TYPE srctype, const TDS_CHAR *src, TDS_UINT srclen,
    1083             :                 TDS_SERVER_TYPE desttype, TDSCOLUMN *col)
    1084             : {
    1085        4708 :         bool variable = true;
    1086             :         CONV_RESULT cr, *p_cr;
    1087             :         TDS_INT len;
    1088        4708 :         BCPCOLDATA *coldata = col->bcp_column_data;
    1089             : 
    1090        4708 :         coldata->is_null = false;
    1091             : 
    1092        4708 :         if (!is_variable_type(desttype)) {
    1093        3304 :                 variable = false;
    1094        3304 :                 p_cr = (CONV_RESULT *) coldata->data;
    1095             :         } else {
    1096             :                 p_cr = &cr;
    1097             :         }
    1098             : 
    1099        4708 :         len = tds_convert(dbproc->tds_socket->conn->tds_ctx, srctype, src, srclen, desttype, p_cr);
    1100        4708 :         if (len < 0) {
    1101          20 :                 _dblib_convert_err(dbproc, len);
    1102             :                 return TDS_FAIL;
    1103             :         }
    1104             : 
    1105        4688 :         coldata->datalen = len;
    1106        4688 :         if (variable) {
    1107        1404 :                 if (len > col->on_server.column_size) {
    1108           0 :                         free(cr.c);
    1109           0 :                         dbperror(dbproc, SYBECOFL, 0);
    1110             :                         return TDS_FAIL;
    1111             :                 }
    1112        1404 :                 free(coldata->data);
    1113        1404 :                 coldata->data = (TDS_UCHAR *) cr.c;
    1114             :         }
    1115             :         return TDS_SUCCESS;
    1116             : }
    1117             : 
    1118             : static void
    1119        4708 : rtrim_bcpcol(TDSCOLUMN *bcpcol)
    1120             : {
    1121             :         /* trim trailing blanks from character data */
    1122        4708 :         if (is_ascii_type(bcpcol->on_server.column_type)) {
    1123             :                 /* A single NUL byte indicates an empty string. */
    1124        1252 :                 if (bcpcol->bcp_column_data->datalen == 1
    1125         206 :                     && bcpcol->bcp_column_data->data[0] == '\0') {
    1126           0 :                         bcpcol->bcp_column_data->datalen = 0;
    1127           0 :                         return;
    1128             :                 }
    1129        2504 :                 bcpcol->bcp_column_data->datalen = rtrim((char *) bcpcol->bcp_column_data->data,
    1130             :                                                                   bcpcol->bcp_column_data->datalen);
    1131        1252 :                 return;
    1132             :         }
    1133             : 
    1134             :         /* unicode part */
    1135        3456 :         if (is_unicode_type(bcpcol->on_server.column_type)) {
    1136             :                 uint16_t *data, space;
    1137             : 
    1138          68 :                 if (!bcpcol->char_conv || bcpcol->char_conv->to.charset.min_bytes_per_char != 2)
    1139           6 :                         return;
    1140             : 
    1141          68 :                 data = (uint16_t *) bcpcol->bcp_column_data->data;
    1142             :                 /* A single NUL byte indicates an empty string. */
    1143          68 :                 if (bcpcol->bcp_column_data->datalen == 2 && data[0] == 0) {
    1144           6 :                         bcpcol->bcp_column_data->datalen = 0;
    1145           6 :                         return;
    1146             :                 }
    1147          62 :                 switch (bcpcol->char_conv->to.charset.canonic) {
    1148           0 :                 case TDS_CHARSET_UTF_16BE:
    1149             :                 case TDS_CHARSET_UCS_2BE:
    1150           0 :                         TDS_PUT_A2BE(&space, 0x20);
    1151           0 :                         break;
    1152          62 :                 case TDS_CHARSET_UTF_16LE:
    1153             :                 case TDS_CHARSET_UCS_2LE:
    1154          62 :                         TDS_PUT_A2LE(&space, 0x20);
    1155          62 :                         break;
    1156             :                 default:
    1157             :                         return;
    1158             :                 }
    1159         124 :                 bcpcol->bcp_column_data->datalen = rtrim_u16(data, bcpcol->bcp_column_data->datalen, space);
    1160             :         }
    1161             : }
    1162             : 
    1163             : /** 
    1164             :  * \ingroup dblib_bcp_internal
    1165             :  * \brief 
    1166             :  *
    1167             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    1168             :  * \param hostfile 
    1169             :  * \param row_error set to true if an error is detected in the row
    1170             :  * \param skip skip the row
    1171             :  * 
    1172             :  * \return MORE_ROWS, NO_MORE_ROWS, or FAIL.
    1173             :  * \sa  BCP_SETL(), bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), bcp_done(), bcp_exec(), bcp_getl(), bcp_init(), bcp_moretext(), bcp_options(), bcp_readfmt(), bcp_sendrow()
    1174             :  */
    1175             : static STATUS
    1176         682 : _bcp_read_hostfile(DBPROCESS *dbproc, TDSFILESTREAM *stream, bool *row_error, bool skip)
    1177             : {
    1178             :         int i;
    1179         682 :         bool truncation_warning = false;
    1180             : 
    1181         682 :         tdsdump_log(TDS_DBG_FUNC, "_bcp_read_hostfile(%p, %p, %p, %d)\n", dbproc, stream, row_error, skip);
    1182         682 :         assert(dbproc);
    1183         682 :         assert(row_error);
    1184             : 
    1185             :         /* for each host file column defined by calls to bcp_colfmt */
    1186             : 
    1187        5166 :         for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
    1188        2448 :                 TDSCOLUMN *bcpcol = NULL;
    1189             :                 BCP_HOSTCOLINFO *hostcol;
    1190        2448 :                 TDS_CHAR *coldata = NULL;
    1191        2448 :                 int collen = 0; /* How many bytes to read from hostfile */
    1192        2448 :                 bool data_is_null = false;
    1193             :                 offset_type col_start;
    1194             : 
    1195        2448 :                 tdsdump_log(TDS_DBG_FUNC, "parsing host column %d\n", i + 1);
    1196        2448 :                 hostcol = dbproc->hostfileinfo->host_columns[i];
    1197             : 
    1198        2448 :                 hostcol->column_error = 0;
    1199             : 
    1200             :                 /* 
    1201             :                  * If this host file column contains table data,
    1202             :                  * find the right element in the table/column list.  
    1203             :                  */
    1204        2448 :                 if (hostcol->tab_colnum > 0) {
    1205        2448 :                         if (hostcol->tab_colnum > dbproc->bcpinfo->bindinfo->num_cols) {
    1206           0 :                                 tdsdump_log(TDS_DBG_FUNC, "error: file wider than table: %d/%d\n", 
    1207             :                                                           i+1, dbproc->bcpinfo->bindinfo->num_cols);
    1208           0 :                                 dbperror(dbproc, SYBEBEOF, 0);
    1209           0 :                                 return FAIL;
    1210             :                         }
    1211        2448 :                         tdsdump_log(TDS_DBG_FUNC, "host column %d uses bcpcol %d (%p)\n", 
    1212             :                                                   i+1, hostcol->tab_colnum, bcpcol);
    1213        2448 :                         bcpcol = dbproc->bcpinfo->bindinfo->columns[hostcol->tab_colnum - 1];
    1214        2448 :                         assert(bcpcol != NULL);
    1215             :                 }
    1216             : 
    1217             :                 /* detect prefix len. NOTE: requires server connection, because
    1218             :                  * it will add a prefix to a prefix-less fixed type if the column
    1219             :                  * is nullable. */
    1220        2448 :                 if (bcpcol && hostcol->prefix_len == -1)
    1221           0 :                         bcp_cache_prefix_len(hostcol, bcpcol);
    1222             : 
    1223             :                 /* If a variable field has no prefix or terminator, its length can
    1224             :                  * only be set by hostcol->column_len.
    1225             :                  *
    1226             :                  * NOTE: Must check do this after bcp_cache_prefix_len() as that
    1227             :                  * could set or unset the prefix_len. */
    1228        2448 :                 if (hostcol->prefix_len == 0 && hostcol->term_len <= 0 && !is_fixed_type(hostcol->datatype)) {
    1229          20 :                         if (hostcol->column_len == -1) {
    1230             :                                 /* If no column max size given either, we can't know how much to read. */
    1231           0 :                                 dbperror(dbproc, SYBEVDPT, 0);
    1232           0 :                                 return FAIL;
    1233             :                         }
    1234             : 
    1235             :                         /* Column size 0, special case to indicate null field. */
    1236          20 :                         if (hostcol->column_len == 0)
    1237          10 :                                 data_is_null = true;
    1238             : 
    1239             :                         collen = hostcol->column_len;
    1240             :                 }
    1241             : 
    1242             :                 /* a prefix length, if extant, specifies how many bytes to read */
    1243        2448 :                 if (hostcol->prefix_len > 0) {
    1244             :                         union {
    1245             :                                 TDS_TINYINT ti;
    1246             :                                 TDS_SMALLINT si;
    1247             :                                 TDS_INT li;
    1248             :                         } u;
    1249             : 
    1250             :                         /* note: prefixes are in native endianness. */
    1251          40 :                         switch (hostcol->prefix_len) {
    1252          30 :                         case 1:
    1253          30 :                                 if (tds_file_stream_read_raw(stream, &u.ti, 1) != 1)
    1254          20 :                                         return _bcp_check_eof(dbproc, stream, i);
    1255          20 :                                 collen = u.ti ? u.ti : -1;
    1256          20 :                                 break;
    1257           0 :                         case 2:
    1258           0 :                                 if (tds_file_stream_read_raw(stream, &u.si, 2) != 2)
    1259           0 :                                         return _bcp_check_eof(dbproc, stream, i);
    1260           0 :                                 collen = u.si;
    1261           0 :                                 break;
    1262          10 :                         case 4:
    1263          10 :                                 if (tds_file_stream_read_raw(stream, &u.li, 4) != 4)
    1264           0 :                                         return _bcp_check_eof(dbproc, stream, i);
    1265          10 :                                 collen = u.li;
    1266          10 :                                 break;
    1267           0 :                         default:
    1268             :                                 /* Should be unreachable - bcp_colfmt() also checked this. */
    1269           0 :                                 dbperror(dbproc, SYBEBCPREF, 0);
    1270           0 :                                 return FAIL;
    1271             :                         }
    1272             : 
    1273             :                         /* TODO test all NULL types */
    1274             :                         /* Length prefix of -1 means a null value. */
    1275          30 :                         if (collen <= -1)
    1276             :                                 data_is_null = true;
    1277             :                 }
    1278             : 
    1279             :                 /* Report an error if a fixed-width type has mismatching prefix.
    1280             :                  * Note: fixed-width types are allowed a prefix in order to be nullable.
    1281             :                  */
    1282        2438 :                 if (!data_is_null && is_fixed_type(hostcol->datatype)) {
    1283          40 :                         int fixed_size = tds_get_size_by_type(hostcol->datatype);
    1284             : 
    1285          40 :                         if (collen > 0 && collen != fixed_size) {
    1286           0 :                                 tdsdump_log(TDS_DBG_FUNC,
    1287             :                                             "bcp_colfmt: invalid collen %d for fixed type %d.\n", collen, hostcol->datatype);
    1288           0 :                                 dbperror(dbproc, SYBECSYN, 0);
    1289           0 :                                 return FAIL;
    1290             :                         }
    1291             : 
    1292             :                         collen = fixed_size;
    1293             :                 }
    1294             : 
    1295        2438 :                 tdsdump_log(TDS_DBG_FUNC, "prefix_len = %d, term_len = %d, collen = %d\n", hostcol->prefix_len, hostcol->term_len,
    1296             :                             collen);
    1297             : 
    1298        2438 :                 col_start = tds_file_stream_tell(stream);
    1299             : 
    1300             :                 /* We will perform iconv on hostfile text only when the field has a
    1301             :                  * terminator, because that indicates it's a text file and would be
    1302             :                  * in the client charset.  Prefixed fields indicate a host-native
    1303             :                  * file, and our tds_bcp_fread() function doesn't support
    1304             :                  * reading an exact number of bytes anyway.
    1305             :                  *
    1306             :                  * NOTE: bcp_colfmt() prevents field having both prefix and terminator.
    1307             :                  */
    1308        2438 :                 if (data_is_null)
    1309             :                         collen = 0;
    1310        2428 :                 else if (hostcol->term_len > 0) {
    1311             :                         size_t col_bytes;
    1312             :                         TDSRET conv_res;
    1313             : 
    1314             :                         /* Note: Important to not stop reading early based on a field width
    1315             :                          * setting (this would cause hostfile to get out of sync). */
    1316        2368 :                         coldata = NULL;
    1317        4736 :                         conv_res = tds_bcp_fread(dbproc->tds_socket, bcpcol ? bcpcol->char_conv : NULL, stream,
    1318        2368 :                                                  (const char *) hostcol->terminator, hostcol->term_len, &coldata, &col_bytes);
    1319             : 
    1320        2368 :                         if (TDS_FAILED(conv_res)) {
    1321           0 :                                 tdsdump_log(TDS_DBG_FUNC, "col %d: error converting %ld bytes!\n",
    1322             :                                                         (i+1), (long) collen);
    1323           0 :                                 *row_error = true;
    1324           0 :                                 free(coldata);
    1325             :                                 /* This case can include columns missing a terminator, and
    1326             :                                  * wrong number of columns in the row, as well as the data not
    1327             :                                  * being of valid form for the column type. */
    1328           0 :                                 dbperror(dbproc, SYBECSYN, 0);
    1329           0 :                                 return FAIL;
    1330             :                         }
    1331             : 
    1332        2368 :                         if (conv_res == TDS_NO_MORE_RESULTS) {
    1333         186 :                                 free(coldata);
    1334         186 :                                 return _bcp_check_eof(dbproc, stream, i);
    1335             :                         }
    1336             : 
    1337        2182 :                         if (col_bytes > 0x7fffffffl) {
    1338           0 :                                 free(coldata);
    1339           0 :                                 *row_error = true;
    1340           0 :                                 tdsdump_log(TDS_DBG_FUNC, "data from file is too large!\n");
    1341           0 :                                 dbperror(dbproc, SYBEBCOR, 0);
    1342           0 :                                 return FAIL;
    1343             :                         }
    1344             : 
    1345             :                         /* collen is the post-iconv size of the field here */
    1346        2182 :                         collen = (int) col_bytes;
    1347        2182 :                         if (collen == 0)
    1348         334 :                                 data_is_null = true;
    1349             : 
    1350             :                         /* To support empty strings and keep compatibility with older files empty strings
    1351             :                          * are encoded as a single NUL byte. */
    1352        2182 :                         if (collen == 1 && coldata[0] == '\0')
    1353          40 :                                 collen = 0;
    1354             : 
    1355             :                         /*
    1356             :                          * TODO:  
    1357             :                          *    Dates are a problem.  In theory, we should be able to read non-English dates, which
    1358             :                          *    would contain non-ASCII characters.  One might suppose we should convert date
    1359             :                          *    strings to ISO-8859-1 (or another canonical form) here, because tds_convert() can't be
    1360             :                          *    expected to deal with encodings. But instead date strings are read verbatim and 
    1361             :                          *    passed to tds_convert() without even waving to iconv().  For English dates, this works, 
    1362             :                          *    because English dates expressed as UTF-8 strings are indistinguishable from the ASCII.  
    1363             :                          */
    1364             :                 } else {        /* Length known due to being a fixed field and/or prefixed. */
    1365          60 :                         assert(collen > 0);  // The above logic should guarantee this.
    1366             : 
    1367          60 :                         coldata = tds_new(TDS_CHAR, 1 + collen);
    1368          60 :                         if (coldata == NULL) {
    1369           0 :                                 *row_error = true;
    1370           0 :                                 dbperror(dbproc, SYBEMEM, errno);
    1371           0 :                                 return FAIL;
    1372             :                         }
    1373             : 
    1374          60 :                         tdsdump_log(TDS_DBG_FUNC, "Reading %d bytes from hostfile.\n", collen);
    1375          60 :                         if (tds_file_stream_read_raw(stream, coldata, collen) != collen) {
    1376          10 :                                 free(coldata);
    1377          10 :                                 return _bcp_check_eof(dbproc, stream, i);
    1378             :                         }
    1379             : 
    1380             :                         /* Not sure why this is here, the terminated-read branch doesn't do it. */
    1381          50 :                         coldata[collen] = 0;
    1382             :                 }
    1383             : 
    1384             :                 /*
    1385             :                  * At this point, however the field was read, however big it was, its
    1386             :                  * address is coldata (which is a dynamically allocated buffer or NULL),
    1387             :                  * and its size is collen.
    1388             :                  * NOTE: we intentionally do not force truncation to hostcol->column_len
    1389             :                  * if a prefix/terminator specified longer data; matching behaviour of MS BCP 16.0.
    1390             :                  */
    1391        2242 :                 tdsdump_log(TDS_DBG_FUNC, "Data read from hostfile: collen is now %d, data_is_null is %d\n", collen, data_is_null);
    1392        2242 :                 if (!skip && bcpcol) {
    1393        2242 :                         if (data_is_null) {
    1394         344 :                                 bcpcol->bcp_column_data->is_null = true;
    1395         344 :                                 bcpcol->bcp_column_data->datalen = 0;
    1396             :                         } else {
    1397             :                                 TDSRET rc;
    1398             :                                 TDS_SERVER_TYPE desttype;
    1399             : 
    1400        1898 :                                 desttype = tds_get_conversion_type(bcpcol->column_type, bcpcol->column_size);
    1401             : 
    1402             :                                 /* _bcp_convert_in will give an error if our char data exceeds
    1403             :                                  * the server column size, so we need to deal with that now
    1404             :                                  */
    1405        1898 :                                 if (desttype == SYBCHAR || desttype == SYBVARCHAR) {
    1406         790 :                                         if (collen > bcpcol->on_server.column_size) {
    1407          20 :                                                 tdsdump_log(TDS_DBG_INFO1,
    1408             :                                                             "Warning: _bcp_read_hostfile: %d bytes at offset 0x%" PRIx64
    1409             :                                                             " in the data file: truncated to server size %d.\n",
    1410             :                                                             collen, (TDS_INT8) col_start, (int) bcpcol->on_server.column_size);
    1411             : 
    1412          20 :                                                 collen = bcpcol->on_server.column_size;
    1413          20 :                                                 truncation_warning = true;
    1414             :                                         }
    1415             :                                 }
    1416             : 
    1417        1898 :                                 rc = _bcp_convert_in(dbproc, hostcol->datatype, (const TDS_CHAR *) coldata, collen,
    1418             :                                                      desttype, bcpcol);
    1419        1898 :                                 if (TDS_FAILED(rc)) {
    1420          20 :                                         hostcol->column_error = HOST_COL_CONV_ERROR;
    1421          20 :                                         *row_error = true;
    1422          20 :                                         tdsdump_log(TDS_DBG_FUNC,
    1423             :                                                     "_bcp_read_hostfile failed to convert %d bytes at offset 0x%" PRIx64
    1424             :                                                     " in the data file.\n", collen, (TDS_INT8) col_start);
    1425             :                                 }
    1426             : 
    1427        1898 :                                 rtrim_bcpcol(bcpcol);
    1428             :                         }
    1429             : #if USING_SYBEBCNN
    1430             :                         if (!hostcol->column_error) {
    1431             :                                 if (bcpcol->bcp_column_data->datalen <= 0) {   /* Are we trying to insert a NULL ? */
    1432             :                                         if (!bcpcol->column_nullable) {
    1433             :                                                 /* too bad if the column is not nullable */
    1434             :                                                 hostcol->column_error = HOST_COL_NULL_ERROR;
    1435             :                                                 *row_error = true;
    1436             :                                                 dbperror(dbproc, SYBEBCNN, 0);
    1437             :                                         }
    1438             :                                 }
    1439             :                         }
    1440             : #endif
    1441             :                 }
    1442        2242 :                 free(coldata);
    1443             :         }
    1444             : 
    1445         476 :         if (dbproc->bcpinfo->dry_run && truncation_warning)
    1446           0 :                 printf("Warning: data truncated due to server column being too small; see log file for detail.\n");
    1447             : 
    1448             :         return MORE_ROWS;
    1449             : }
    1450             : 
    1451             : /** 
    1452             :  * \ingroup dblib_bcp
    1453             :  * \brief Write data in host variables to the table.  
    1454             :  * 
    1455             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    1456             :  * 
    1457             :  * \remarks Call bcp_bind() first to describe the variables to be used.  
    1458             :  *      Use bcp_batch() to commit sets of rows. 
    1459             :  *      After sending the last row call bcp_done().
    1460             :  * \return SUCCEED or FAIL.
    1461             :  * \sa  bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(), 
    1462             :  *      bcp_control(), bcp_done(), bcp_exec(), bcp_init(), bcp_moretext(), bcp_options()
    1463             :  */
    1464             : RETCODE
    1465         180 : bcp_sendrow(DBPROCESS * dbproc)
    1466             : {
    1467             :         TDSSOCKET *tds;
    1468             : 
    1469         180 :         tdsdump_log(TDS_DBG_FUNC, "bcp_sendrow(%p)\n", dbproc);
    1470         180 :         CHECK_CONN(FAIL);
    1471         180 :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
    1472             : 
    1473         180 :         tds = dbproc->tds_socket;
    1474             : 
    1475         180 :         if (dbproc->bcpinfo->direction != DB_IN) {
    1476           0 :                 dbperror(dbproc, SYBEBCPN, 0);
    1477           0 :                 return FAIL;
    1478             :         }
    1479             : 
    1480         180 :         if (dbproc->hostfileinfo != NULL) {
    1481           0 :                 dbperror(dbproc, SYBEBCPB, 0);
    1482           0 :                 return FAIL;
    1483             :         }
    1484             : 
    1485             :         /* 
    1486             :          * The first time sendrow is called after bcp_init,
    1487             :          * there is a certain amount of initialisation to be done.
    1488             :          */
    1489         180 :         if (!dbproc->bcpinfo->xfer_init) {
    1490             : 
    1491             :                 /* The start_copy function retrieves details of the table's columns */
    1492          28 :                 if (TDS_FAILED(tds_bcp_start_copy_in(tds, dbproc->bcpinfo))) {
    1493           0 :                         dbperror(dbproc, SYBEBULKINSERT, 0);
    1494           0 :                         return FAIL;
    1495             :                 }
    1496             : 
    1497          28 :                 dbproc->bcpinfo->xfer_init = true;
    1498             : 
    1499             :         }
    1500             : 
    1501         180 :         dbproc->bcpinfo->parent = dbproc;
    1502         180 :         return TDS_FAILED(tds_bcp_send_record(dbproc->tds_socket, dbproc->bcpinfo,
    1503         180 :                           _bcp_get_col_data, _bcp_null_error, 0)) ? FAIL : SUCCEED;
    1504             : }
    1505             : 
    1506             : 
    1507             : /** 
    1508             :  * \ingroup dblib_bcp_internal
    1509             :  * \brief 
    1510             :  *
    1511             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    1512             :  * \param rows_copied 
    1513             :  * 
    1514             :  * \return SUCCEED or FAIL.
    1515             :  * \sa  BCP_SETL(), bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), bcp_done(), bcp_exec(), bcp_getl(), bcp_init(), bcp_moretext(), bcp_options(), bcp_readfmt(), bcp_sendrow()
    1516             :  */
    1517             : static RETCODE
    1518         206 : _bcp_exec_in(DBPROCESS *dbproc, DBINT *rows_copied)
    1519             : {
    1520         206 :         FILE *errfile = NULL;
    1521             :         TDSFILESTREAM hoststream;
    1522         206 :         TDSSOCKET *tds = dbproc->tds_socket;
    1523             :         BCP_HOSTCOLINFO *hostcol;
    1524             :         STATUS ret;
    1525             : 
    1526             :         int i, rows_written_so_far;
    1527             :         TDS_INT row_of_hostfile;
    1528             :         int row_error_count;
    1529             :         bool row_error;
    1530             :         offset_type row_start, row_end;
    1531             :         offset_type error_row_size;
    1532         206 :         const size_t chunk_size = 0x20000u;
    1533             :         
    1534         206 :         tdsdump_log(TDS_DBG_FUNC, "_bcp_exec_in(%p, %p)\n", dbproc, rows_copied);
    1535             :         assert(dbproc);
    1536         206 :         assert(rows_copied);
    1537             : 
    1538         206 :         *rows_copied = 0;
    1539             : 
    1540         206 :         if (!TDS_SUCCEED(tds_file_stream_init(&hoststream, fopen(dbproc->hostfileinfo->hostfile, "rb")))) {
    1541           0 :                 tdsdump_log(TDS_DBG_FUNC, "error: cannot initialize hostfile stream");
    1542           0 :                 dbperror(dbproc, SYBEBCUO, 0);
    1543           0 :                 return FAIL;
    1544             :         }
    1545             : 
    1546         206 :         if (TDS_FAILED(tds_bcp_start_copy_in(tds, dbproc->bcpinfo))) {
    1547           0 :                 tds_file_stream_close(&hoststream);
    1548           0 :                 return FAIL;
    1549             :         }
    1550             : 
    1551         206 :         row_of_hostfile = 0;
    1552         206 :         rows_written_so_far = 0;
    1553             : 
    1554         206 :         row_error_count = 0;
    1555         206 :         dbproc->bcpinfo->parent = dbproc;
    1556             : 
    1557             :         for (;;) {
    1558             :                 bool skip;
    1559             : 
    1560         682 :                 row_start = tds_file_stream_tell(&hoststream);
    1561         682 :                 row_error = false;
    1562             : 
    1563         682 :                 row_of_hostfile++;
    1564             : 
    1565         682 :                 if (dbproc->hostfileinfo->lastrow > 0 && row_of_hostfile > dbproc->hostfileinfo->lastrow)
    1566             :                         break;
    1567             : 
    1568         682 :                 skip = dbproc->hostfileinfo->firstrow > row_of_hostfile;
    1569         682 :                 ret = _bcp_read_hostfile(dbproc, &hoststream, &row_error, skip);
    1570         682 :                 if (ret != MORE_ROWS)
    1571             :                         break;
    1572             : 
    1573         476 :                 if (row_error) {
    1574             :                         int count;
    1575             : 
    1576          20 :                         if (errfile == NULL && dbproc->hostfileinfo->errorfile) {
    1577          10 :                                 if (!(errfile = fopen(dbproc->hostfileinfo->errorfile, "wb"))) {
    1578           0 :                                         tds_file_stream_close(&hoststream);
    1579           0 :                                         dbperror(dbproc, SYBEBUOE, 0);
    1580           0 :                                         return FAIL;
    1581             :                                 }
    1582             :                         }
    1583             : 
    1584          20 :                         if (errfile != NULL) {
    1585             :                                 char *row_in_error = NULL;
    1586             : 
    1587             : #ifdef _WIN32
    1588             : #define TDS_EOL "\r\n"
    1589             : #else
    1590             : #define TDS_EOL "\n"
    1591             : #endif
    1592             : 
    1593          20 :                                 for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
    1594          20 :                                         hostcol = dbproc->hostfileinfo->host_columns[i];
    1595          20 :                                         if (hostcol->column_error == HOST_COL_CONV_ERROR) {
    1596          20 :                                                 count = fprintf(errfile,
    1597             :                                                                 "#@ data conversion error on host data file "
    1598             :                                                                 "Row %d Column %d" TDS_EOL, (int) row_of_hostfile, i + 1);
    1599          20 :                                                 if (count < 0) {
    1600           0 :                                                         dbperror(dbproc, SYBEBWEF, errno);
    1601             :                                                 }
    1602           0 :                                         } else if (hostcol->column_error == HOST_COL_NULL_ERROR) {
    1603           0 :                                                 count = fprintf(errfile, "#@ Attempt to bulk-copy a NULL value into Server column"
    1604             :                                                                 " which does not accept NULL values. Row %d, Column %d" TDS_EOL,
    1605             :                                                                 row_of_hostfile, i + 1);
    1606           0 :                                                 if (count < 0)
    1607           0 :                                                         dbperror(dbproc, SYBEBWEF, errno);
    1608             :                                         }
    1609             :                                 }
    1610             : 
    1611          20 :                                 row_end = tds_file_stream_tell(&hoststream);
    1612             : 
    1613             :                                 /* error data can be very long so split in chunks */
    1614          20 :                                 error_row_size = row_end - row_start;
    1615          20 :                                 tds_file_stream_seek_set(&hoststream, row_start);
    1616             : 
    1617          60 :                                 while (error_row_size > 0) {
    1618          20 :                                         size_t chunk = TDS_MIN((size_t) error_row_size, chunk_size);
    1619             :                                         size_t written;
    1620             : 
    1621          20 :                                         if (!row_in_error) {
    1622          20 :                                                 if ((row_in_error = tds_new(char, chunk)) == NULL) {
    1623           0 :                                                         dbperror(dbproc, SYBEMEM, errno);
    1624             :                                                 }
    1625             :                                         }
    1626             : 
    1627          20 :                                         if (tds_file_stream_read_raw(&hoststream, row_in_error, chunk) != chunk)
    1628           0 :                                                 tdsdump_log(TDS_DBG_ERROR, "BILL fread failed after fseek\n");
    1629             : 
    1630          20 :                                         written = fwrite(row_in_error, 1, chunk, errfile);
    1631          20 :                                         if (written < chunk)
    1632           0 :                                                 dbperror(dbproc, SYBEBWEF, errno);
    1633             : 
    1634          20 :                                         error_row_size -= chunk;
    1635             :                                 }
    1636          20 :                                 free(row_in_error);
    1637             : 
    1638          20 :                                 tds_file_stream_seek_set(&hoststream, row_end);
    1639          20 :                                 count = fprintf(errfile, TDS_EOL);
    1640          20 :                                 if (count < 0)
    1641           0 :                                         dbperror(dbproc, SYBEBWEF, errno);
    1642             :                         }
    1643          20 :                         row_error_count++;
    1644          20 :                         if (row_error_count >= dbproc->hostfileinfo->maxerrs)
    1645             :                                 break;
    1646          20 :                         continue;
    1647             :                 }
    1648             : 
    1649         456 :                 if (skip)
    1650           0 :                         continue;
    1651             : 
    1652         456 :                 if (dbproc->bcpinfo->dry_run) {
    1653           0 :                         ++rows_written_so_far;
    1654           0 :                         continue;
    1655             :                 }
    1656             : 
    1657         456 :                 if (TDS_SUCCEED(tds_bcp_send_record(dbproc->tds_socket, dbproc->bcpinfo, _bcp_no_get_col_data, _bcp_null_error, 0))) {
    1658             : 
    1659         456 :                         rows_written_so_far++;
    1660             : 
    1661         456 :                         if (dbproc->hostfileinfo->batch > 0 && rows_written_so_far == dbproc->hostfileinfo->batch) {
    1662           0 :                                 if (TDS_FAILED(tds_bcp_done(tds, &rows_written_so_far))) {
    1663           0 :                                         if (errfile)
    1664           0 :                                                 fclose(errfile);
    1665           0 :                                         tds_file_stream_close(&hoststream);
    1666           0 :                                         return FAIL;
    1667             :                                 }
    1668             : 
    1669           0 :                                 *rows_copied += rows_written_so_far;
    1670           0 :                                 rows_written_so_far = 0;
    1671             : 
    1672           0 :                                 dbperror(dbproc, SYBEBBCI, 0); /* batch copied to server */
    1673             : 
    1674           0 :                                 tds_bcp_start(tds, dbproc->bcpinfo);
    1675             :                         }
    1676             :                 }
    1677             :         }
    1678             :         
    1679         206 :         if (row_error_count == 0 && row_of_hostfile < dbproc->hostfileinfo->firstrow) {
    1680             :                 /* "The BCP hostfile '%1!' contains only %2! rows.  */
    1681           0 :                 dbperror(dbproc, SYBEBCSA, 0, dbproc->hostfileinfo->hostfile, row_of_hostfile); 
    1682             :         }
    1683             : 
    1684         206 :         if (errfile &&  0 != fclose(errfile) ) {
    1685           0 :                 dbperror(dbproc, SYBEBUCE, 0);
    1686             :         }
    1687             : 
    1688         206 :         if (TDS_FAILED(tds_file_stream_close(&hoststream))) {
    1689           0 :                 dbperror(dbproc, SYBEBCUC, 0);
    1690           0 :                 ret = FAIL;
    1691             :         }
    1692             : 
    1693         206 :         if (!dbproc->bcpinfo->dry_run)
    1694         206 :                 tds_bcp_done(tds, &rows_written_so_far);
    1695             : 
    1696         206 :         *rows_copied += rows_written_so_far;
    1697             : 
    1698         206 :         return ret == NO_MORE_ROWS ? SUCCEED : FAIL;    /* (ret is returned from _bcp_read_hostfile) */
    1699             : }
    1700             : 
    1701             : /** 
    1702             :  * \ingroup dblib_bcp
    1703             :  * \brief Write a datafile to a table. 
    1704             :  *
    1705             :  * 
    1706             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    1707             :  * \param rows_copied bcp_exec will write the count of rows successfully written to this address. 
    1708             :  *      If \a rows_copied is NULL, it will be ignored by db-lib. 
    1709             :  *
    1710             :  * \return SUCCEED or FAIL.
    1711             :  * \sa  bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(),
    1712             :  *      bcp_control(), bcp_done(), bcp_init(), bcp_sendrow()
    1713             :  */
    1714             : RETCODE
    1715         402 : bcp_exec(DBPROCESS * dbproc, DBINT *rows_copied)
    1716             : {
    1717             :         DBINT dummy_copied;
    1718         402 :         RETCODE ret = FAIL;
    1719             : 
    1720         402 :         tdsdump_log(TDS_DBG_FUNC, "bcp_exec(%p, %p)\n", dbproc, rows_copied);
    1721         402 :         CHECK_CONN(FAIL);
    1722         402 :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
    1723         402 :         CHECK_PARAMETER(dbproc->hostfileinfo, SYBEBCVH, FAIL);
    1724             : 
    1725         402 :         if (rows_copied == NULL) /* NULL means we should ignore it */
    1726           0 :                 rows_copied = &dummy_copied;
    1727             : 
    1728         402 :         if (dbproc->bcpinfo->direction == DB_OUT || dbproc->bcpinfo->direction == DB_QUERYOUT) {
    1729         196 :                 ret = _bcp_exec_out(dbproc, rows_copied);
    1730         206 :         } else if (dbproc->bcpinfo->direction == DB_IN) {
    1731         206 :                 ret = _bcp_exec_in(dbproc, rows_copied);
    1732             :         }
    1733         402 :         _bcp_free_storage(dbproc);
    1734             :         
    1735         402 :         return ret;
    1736             : }
    1737             : 
    1738             : /** 
    1739             :  * \ingroup dblib_bcp_internal
    1740             :  * \brief 
    1741             :  *
    1742             :  * \param buffer 
    1743             :  * \param size 
    1744             :  * \param f 
    1745             :  * 
    1746             :  * \return SUCCEED or FAIL.
    1747             :  * \sa  BCP_SETL(), bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), bcp_done(), bcp_exec(), bcp_getl(), bcp_init(), bcp_moretext(), bcp_options(), bcp_readfmt(), bcp_sendrow()
    1748             :  */
    1749             : static char *
    1750         160 : _bcp_fgets(char *buffer, int size, FILE *f)
    1751             : {
    1752         160 :         char *p = fgets(buffer, size, f);
    1753         160 :         if (p == NULL) 
    1754             :                 return p;
    1755             : 
    1756             :         /* discard newline */
    1757         160 :         p = strchr(buffer, 0) - 1;
    1758         160 :         if (p >= buffer && *p == '\n')
    1759         160 :                 *p = 0;
    1760             :         return buffer;
    1761             : }
    1762             : 
    1763             : /** 
    1764             :  * \ingroup dblib_bcp
    1765             :  * \brief Read a format definition file.
    1766             :  *
    1767             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    1768             :  * \param filename Name that will be passed to fopen(3).  
    1769             :  * 
    1770             :  * \remarks Reads a format file and calls bcp_columns() and bcp_colfmt() as needed. 
    1771             :  *
    1772             :  * \return SUCCEED or FAIL.
    1773             :  * \sa  bcp_colfmt(), bcp_colfmt_ps(), bcp_columns(), bcp_writefmt()
    1774             :  */
    1775             : RETCODE
    1776          20 : bcp_readfmt(DBPROCESS * dbproc, const char filename[])
    1777             : {
    1778             :         BCP_HOSTCOLINFO hostcol[1];
    1779             :         FILE *ffile;
    1780             :         char buffer[1024];
    1781          20 :         float lf_version = 0.0;
    1782          20 :         int li_numcols = 0;
    1783          20 :         int colinfo_count = 0;
    1784             : 
    1785          20 :         tdsdump_log(TDS_DBG_FUNC, "bcp_readfmt(%p, %s)\n", dbproc, filename? filename:"NULL");
    1786          20 :         CHECK_CONN(FAIL);
    1787          20 :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
    1788          20 :         CHECK_NULP(filename, "bcp_readfmt", 2, FAIL);
    1789             : 
    1790          20 :         memset(hostcol, 0, sizeof(hostcol));
    1791             : 
    1792          20 :         if ((ffile = fopen(filename, "r")) == NULL) {
    1793           0 :                 dbperror(dbproc, SYBEBUOF, 0);
    1794           0 :                 goto Cleanup;
    1795             :         }
    1796             : 
    1797          20 :         if ((_bcp_fgets(buffer, sizeof(buffer), ffile)) != NULL) {
    1798          20 :                 lf_version = (float)atof(buffer);
    1799           0 :         } else if (ferror(ffile)) {
    1800           0 :                 dbperror(dbproc, SYBEBRFF, errno);
    1801           0 :                 goto Cleanup;
    1802             :         }
    1803             : 
    1804          20 :         if ((_bcp_fgets(buffer, sizeof(buffer), ffile)) != NULL) {
    1805          20 :                 li_numcols = atoi(buffer);
    1806           0 :         } else if (ferror(ffile)) {
    1807           0 :                 dbperror(dbproc, SYBEBRFF, errno);
    1808           0 :                 goto Cleanup;
    1809             :         }
    1810             : 
    1811          20 :         if (li_numcols <= 0)
    1812             :                 goto Cleanup;
    1813             : 
    1814          20 :         if (bcp_columns(dbproc, li_numcols) == FAIL)
    1815             :                 goto Cleanup;
    1816             : 
    1817             :         do {
    1818         120 :                 memset(hostcol, 0, sizeof(hostcol));
    1819             : 
    1820         120 :                 if (_bcp_fgets(buffer, sizeof(buffer), ffile) == NULL)
    1821             :                         goto Cleanup;
    1822             : 
    1823         120 :                 if (!_bcp_readfmt_colinfo(dbproc, buffer, hostcol))
    1824             :                         goto Cleanup;
    1825             : 
    1826         240 :                 if (bcp_colfmt(dbproc, hostcol->host_column, hostcol->datatype,
    1827             :                                hostcol->prefix_len, hostcol->column_len,
    1828         120 :                                hostcol->terminator, hostcol->term_len, hostcol->tab_colnum) == FAIL) {
    1829             :                         goto Cleanup;
    1830             :                 }
    1831             : 
    1832         120 :                 TDS_ZERO_FREE(hostcol->terminator);
    1833         120 :         } while (++colinfo_count < li_numcols);
    1834             : 
    1835          20 :         if (ferror(ffile)) {
    1836           0 :                 dbperror(dbproc, SYBEBRFF, errno);
    1837           0 :                 goto Cleanup;
    1838             :         }
    1839             :         
    1840          20 :         if (fclose(ffile) != 0) {
    1841           0 :                 dbperror(dbproc, SYBEBUCF, 0);
    1842             :                 /* even if failure is returned ffile is no more valid */
    1843           0 :                 ffile = NULL;
    1844           0 :                 goto Cleanup;
    1845             :         }
    1846          20 :         ffile = NULL;
    1847             : 
    1848          20 :         if (colinfo_count != li_numcols)
    1849             :                 goto Cleanup;
    1850             : 
    1851             :         return SUCCEED;
    1852             : 
    1853           0 : Cleanup:
    1854           0 :         TDS_ZERO_FREE(hostcol->terminator);
    1855           0 :         _bcp_free_columns(dbproc);
    1856           0 :         if (ffile)
    1857           0 :                 fclose(ffile);
    1858             :         return FAIL;
    1859             : }
    1860             : 
    1861             : /** 
    1862             :  * \ingroup dblib_bcp_internal
    1863             :  * \brief 
    1864             :  *
    1865             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    1866             :  * \param buf 
    1867             :  * \param ci 
    1868             :  * 
    1869             :  * \return SUCCEED or FAIL.
    1870             :  * \sa  BCP_SETL(), bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), bcp_done(), bcp_exec(), bcp_getl(), bcp_init(), bcp_moretext(), bcp_options(), bcp_readfmt(), bcp_sendrow()
    1871             :  */
    1872             : static int
    1873         120 : _bcp_readfmt_colinfo(DBPROCESS * dbproc, char *buf, BCP_HOSTCOLINFO * ci)
    1874             : {
    1875             :         char *tok;
    1876             :         int whichcol;
    1877             :         char term[30];
    1878             :         int i;
    1879             :         char *lasts;
    1880             : 
    1881             :         enum nextcol
    1882             :         {
    1883             :                 HOST_COLUMN,
    1884             :                 DATATYPE,
    1885             :                 PREFIX_LEN,
    1886             :                 COLUMN_LEN,
    1887             :                 TERMINATOR,
    1888             :                 TAB_COLNUM,
    1889             :                 NO_MORE_COLS
    1890             :         };
    1891             : 
    1892         120 :         assert(dbproc);
    1893         120 :         assert(buf);
    1894         120 :         assert(ci);
    1895         120 :         tdsdump_log(TDS_DBG_FUNC, "_bcp_readfmt_colinfo(%p, %s, %p)\n", dbproc, buf, ci);
    1896             : 
    1897         120 :         tok = strtok_r(buf, " \t", &lasts);
    1898         120 :         whichcol = HOST_COLUMN;
    1899             : 
    1900             :         /* TODO use a better way to get an int atoi is very error prone */
    1901         960 :         while (tok != NULL && whichcol != NO_MORE_COLS) {
    1902         720 :                 switch (whichcol) {
    1903             : 
    1904         120 :                 case HOST_COLUMN:
    1905         120 :                         ci->host_column = atoi(tok);
    1906             : 
    1907         120 :                         if (ci->host_column < 1) {
    1908           0 :                                 dbperror(dbproc, SYBEBIHC, 0);
    1909           0 :                                 return (FALSE);
    1910             :                         }
    1911             : 
    1912             :                         whichcol = DATATYPE;
    1913             :                         break;
    1914             : 
    1915         120 :                 case DATATYPE:
    1916         120 :                         if (strcmp(tok, "SYBCHAR") == 0)
    1917          80 :                                 ci->datatype = SYBCHAR;
    1918          40 :                         else if (strcmp(tok, "SYBTEXT") == 0)
    1919           0 :                                 ci->datatype = SYBTEXT;
    1920          40 :                         else if (strcmp(tok, "SYBBINARY") == 0)
    1921           0 :                                 ci->datatype = SYBBINARY;
    1922          40 :                         else if (strcmp(tok, "SYBIMAGE") == 0)
    1923           0 :                                 ci->datatype = SYBIMAGE;
    1924          40 :                         else if (strcmp(tok, "SYBINT1") == 0)
    1925           0 :                                 ci->datatype = SYBINT1;
    1926          40 :                         else if (strcmp(tok, "SYBINT2") == 0)
    1927           0 :                                 ci->datatype = SYBINT2;
    1928          40 :                         else if (strcmp(tok, "SYBINT4") == 0)
    1929          40 :                                 ci->datatype = SYBINT4;
    1930           0 :                         else if (strcmp(tok, "SYBINT8") == 0)
    1931           0 :                                 ci->datatype = SYBINT8;
    1932           0 :                         else if (strcmp(tok, "SYBFLT8") == 0)
    1933           0 :                                 ci->datatype = SYBFLT8;
    1934           0 :                         else if (strcmp(tok, "SYBREAL") == 0)
    1935           0 :                                 ci->datatype = SYBREAL;
    1936           0 :                         else if (strcmp(tok, "SYBBIT") == 0)
    1937           0 :                                 ci->datatype = SYBBIT;
    1938           0 :                         else if (strcmp(tok, "SYBNUMERIC") == 0)
    1939           0 :                                 ci->datatype = SYBNUMERIC;
    1940           0 :                         else if (strcmp(tok, "SYBDECIMAL") == 0)
    1941           0 :                                 ci->datatype = SYBDECIMAL;
    1942           0 :                         else if (strcmp(tok, "SYBMONEY") == 0)
    1943           0 :                                 ci->datatype = SYBMONEY;
    1944           0 :                         else if (strcmp(tok, "SYBMONEY4") == 0)
    1945           0 :                                 ci->datatype = SYBMONEY4;
    1946           0 :                         else if (strcmp(tok, "SYBDATETIME") == 0)
    1947           0 :                                 ci->datatype = SYBDATETIME;
    1948           0 :                         else if (strcmp(tok, "SYBDATETIME4") == 0)
    1949           0 :                                 ci->datatype = SYBDATETIME4;
    1950             :                         /* TODO SQL* for MS
    1951             :                            SQLNCHAR SQLBIGINT SQLTINYINT SQLSMALLINT
    1952             :                            SQLUNIQUEID SQLVARIANT SQLUDT */
    1953             :                         else {
    1954           0 :                                 dbperror(dbproc, SYBEBUDF, 0);
    1955           0 :                                 return (FALSE);
    1956             :                         }
    1957             : 
    1958             :                         whichcol = PREFIX_LEN;
    1959             :                         break;
    1960             : 
    1961         120 :                 case PREFIX_LEN:
    1962         120 :                         ci->prefix_len = atoi(tok);
    1963         120 :                         whichcol = COLUMN_LEN;
    1964         120 :                         break;
    1965         120 :                 case COLUMN_LEN:
    1966         120 :                         ci->column_len = atoi(tok);
    1967         120 :                         whichcol = TERMINATOR;
    1968         120 :                         break;
    1969         120 :                 case TERMINATOR:
    1970             : 
    1971         120 :                         if (*tok++ != '\"')
    1972             :                                 return (FALSE);
    1973             : 
    1974          40 :                         for (i = 0; *tok != '\"' && i < sizeof(term); i++) {
    1975          40 :                                 if (*tok == '\\') {
    1976          40 :                                         tok++;
    1977          40 :                                         switch (*tok) {
    1978          20 :                                         case 't':
    1979          20 :                                                 term[i] = '\t';
    1980          20 :                                                 break;
    1981          20 :                                         case 'n':
    1982          20 :                                                 term[i] = '\n';
    1983          20 :                                                 break;
    1984           0 :                                         case 'r':
    1985           0 :                                                 term[i] = '\r';
    1986           0 :                                                 break;
    1987           0 :                                         case '\\':
    1988           0 :                                                 term[i] = '\\';
    1989           0 :                                                 break;
    1990           0 :                                         case '0':
    1991           0 :                                                 term[i] = '\0';
    1992           0 :                                                 break;
    1993             :                                         default:
    1994             :                                                 return (FALSE);
    1995             :                                         }
    1996          40 :                                         tok++;
    1997             :                                 } else
    1998           0 :                                         term[i] = *tok++;
    1999             :                         }
    2000             : 
    2001         120 :                         if (*tok != '\"')
    2002             :                                 return (FALSE);
    2003             : 
    2004         120 :                         ci->term_len = i;
    2005         120 :                         TDS_ZERO_FREE(ci->terminator);
    2006         120 :                         if (i > 0) {
    2007          40 :                                 if ((ci->terminator = tds_new(BYTE, i)) == NULL) {
    2008           0 :                                         dbperror(dbproc, SYBEMEM, errno);
    2009           0 :                                         return FALSE;
    2010             :                                 }
    2011          40 :                                 memcpy(ci->terminator, term, i);
    2012             :                         }
    2013             : 
    2014             :                         whichcol = TAB_COLNUM;
    2015             :                         break;
    2016             : 
    2017         120 :                 case TAB_COLNUM:
    2018         120 :                         ci->tab_colnum = atoi(tok);
    2019         120 :                         whichcol = NO_MORE_COLS;
    2020         120 :                         break;
    2021             : 
    2022             :                 }
    2023         720 :                 tok = strtok_r(NULL, " \t", &lasts);
    2024             :         }
    2025         120 :         if (whichcol == NO_MORE_COLS)
    2026             :                 return (TRUE);
    2027             :         else
    2028           0 :                 return (FALSE);
    2029             : }
    2030             : 
    2031             : #if defined(DBLIB_UNIMPLEMENTED)
    2032             : /** 
    2033             :  * \ingroup dblib_bcp
    2034             :  * \brief Write a format definition file. Not Implemented. 
    2035             :  *
    2036             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    2037             :  * \param filename Name that would be passed to fopen(3).  
    2038             :  * 
    2039             :  * \remarks Reads a format file and calls bcp_columns() and bcp_colfmt() as needed. 
    2040             :  * \a FreeTDS includes freebcp, a utility to copy data to or from a host file. 
    2041             :  *
    2042             :  * \todo For completeness, \a freebcp ought to be able to create format files, but that functionality 
    2043             :  *      is currently lacking, as is bcp_writefmt().
    2044             :  * \todo See the vendors' documentation for the format of these files.
    2045             :  *
    2046             :  * \return SUCCEED or FAIL.
    2047             :  * \sa  bcp_colfmt(), bcp_colfmt_ps(), bcp_columns(), bcp_readfmt()
    2048             :  */
    2049             : RETCODE
    2050             : bcp_writefmt(DBPROCESS * dbproc, const char filename[])
    2051             : {
    2052             :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED: bcp_writefmt(%p, %s)\n", dbproc, filename? filename:"NULL");
    2053             :         CHECK_CONN(FAIL);
    2054             :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
    2055             :         CHECK_NULP(filename, "bcp_writefmt", 2, FAIL);
    2056             : 
    2057             : #if 0
    2058             :         dbperror(dbproc, SYBEBUFF, errno);      /* bcp: Unable to create format file */
    2059             :         dbperror(dbproc, SYBEBWFF, errno);      /* I/O error while writing bcp format file */
    2060             : #endif
    2061             : 
    2062             :         return FAIL;
    2063             : }
    2064             : 
    2065             : /** 
    2066             :  * \ingroup dblib_bcp
    2067             :  * \brief Write some text or image data to the server.  Not implemented, sadly.  
    2068             :  *
    2069             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    2070             :  * \param size How much to write, in bytes. 
    2071             :  * \param text Address of the data to be written. 
    2072             :  * \remarks For a SYBTEXT or SYBIMAGE column, bcp_bind() can be called with 
    2073             :  *      a NULL varaddr parameter.  If it is, bcp_sendrow() will return control
    2074             :  *      to the application after the non-text data have been sent.  The application then calls 
    2075             :  *      bcp_moretext() -- usually in a loop -- to send the text data in manageable chunks.  
    2076             :  * \todo implement bcp_moretext().
    2077             :  * \return SUCCEED or FAIL.
    2078             :  * \sa  bcp_bind(), bcp_sendrow(), dbmoretext(), dbwritetext()
    2079             :  */
    2080             : RETCODE
    2081             : bcp_moretext(DBPROCESS * dbproc, DBINT size, BYTE * text)
    2082             : {
    2083             :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED: bcp_moretext(%p, %d, %p)\n", dbproc, size, text);
    2084             :         CHECK_CONN(FAIL);
    2085             :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
    2086             :         CHECK_NULP(text, "bcp_moretext", 3, FAIL);
    2087             :         
    2088             : #if 0
    2089             :         dbperror(dbproc, SYBEBCMTXT, 0); 
    2090             :                 /* bcp_moretext may be used only when there is at least one text or image column in the server table */
    2091             :         dbperror(dbproc, SYBEBTMT, 0); 
    2092             :                 /* Attempt to send too much text data via the bcp_moretext call */
    2093             : #endif
    2094             :         return FAIL;
    2095             : }
    2096             : #endif
    2097             : 
    2098             : /** 
    2099             :  * \ingroup dblib_bcp
    2100             :  * \brief Commit a set of rows to the table. 
    2101             :  * 
    2102             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    2103             :  * \remarks If not called, bcp_done() will cause the rows to be saved.  
    2104             :  * \return Count of rows saved, or -1 on error.
    2105             :  * \sa  bcp_bind(), bcp_done(), bcp_sendrow()
    2106             :  */
    2107             : DBINT
    2108          10 : bcp_batch(DBPROCESS * dbproc)
    2109             : {
    2110          10 :         int rows_copied = 0;
    2111             : 
    2112          10 :         tdsdump_log(TDS_DBG_FUNC, "bcp_batch(%p)\n", dbproc);
    2113          10 :         CHECK_CONN(-1);
    2114          10 :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, -1);
    2115             : 
    2116          10 :         if (TDS_FAILED(tds_bcp_done(dbproc->tds_socket, &rows_copied)))
    2117             :                 return -1;
    2118             : 
    2119          10 :         tds_bcp_start(dbproc->tds_socket, dbproc->bcpinfo);
    2120             : 
    2121          10 :         return rows_copied;
    2122             : }
    2123             : 
    2124             : /** 
    2125             :  * \ingroup dblib_bcp
    2126             :  * \brief Conclude the transfer of data from program variables.
    2127             :  * 
    2128             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    2129             :  * \remarks Do not overlook this function.  According to Sybase, failure to call bcp_done() 
    2130             :  * "will result in unpredictable errors".
    2131             :  * \return As with bcp_batch(), the count of rows saved, or -1 on error.
    2132             :  * \sa  bcp_batch(), bcp_bind(), bcp_moretext(), bcp_sendrow()
    2133             :  */
    2134             : DBINT
    2135          38 : bcp_done(DBPROCESS * dbproc)
    2136             : {
    2137             :         int rows_copied;
    2138             : 
    2139          38 :         tdsdump_log(TDS_DBG_FUNC, "bcp_done(%p)\n", dbproc);
    2140          38 :         CHECK_CONN(-1);
    2141             :         
    2142          38 :         if (!(dbproc->bcpinfo))
    2143             :                 return -1;
    2144             : 
    2145          38 :         if (TDS_FAILED(tds_bcp_done(dbproc->tds_socket, &rows_copied)))
    2146             :                 return -1;
    2147             : 
    2148          20 :         _bcp_free_storage(dbproc);
    2149             : 
    2150          20 :         return rows_copied;
    2151             : }
    2152             : 
    2153             : /** 
    2154             :  * \ingroup dblib_bcp
    2155             :  * \brief Bind a program host variable to a database column
    2156             :  * 
    2157             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    2158             :  * \param varaddr address of host variable
    2159             :  * \param prefixlen length of any prefix found at the beginning of \a varaddr, in bytes.  
    2160             :         Use zero for fixed-length datatypes. 
    2161             :  * \param varlen bytes of data in \a varaddr.  Zero for NULL, -1 for fixed-length datatypes. 
    2162             :  * \param terminator byte sequence that marks the end of the data in \a varaddr
    2163             :  * \param termlen length of \a terminator
    2164             :  * \param vartype datatype of the host variable
    2165             :  * \param table_column Nth column, starting at 1, in the table.
    2166             :  * 
    2167             :  * \remarks The order of operation is:
    2168             :  *      - bcp_init() with \a hfile == NULL and \a direction == DB_IN.
    2169             :  *      - bcp_bind(), once per column you want to write to
    2170             :  *      - bcp_batch(), optionally, to commit a set of rows
    2171             :  *      - bcp_done() 
    2172             :  * \return SUCCEED or FAIL.
    2173             :  * \sa  bcp_batch(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), 
    2174             :  *      bcp_done(), bcp_exec(), bcp_moretext(), bcp_sendrow() 
    2175             :  */
    2176             : RETCODE
    2177         324 : bcp_bind(DBPROCESS * dbproc, BYTE * varaddr, int prefixlen, DBINT varlen,
    2178             :          BYTE * terminator, int termlen, int db_vartype, int table_column)
    2179             : {
    2180             :         TDS_SERVER_TYPE vartype;
    2181             :         TDSCOLUMN *colinfo;
    2182             : 
    2183         324 :         tdsdump_log(TDS_DBG_FUNC, "bcp_bind(%p, %p, %d, %d -- %p, %d, %s, %d)\n", 
    2184             :                                                 dbproc, varaddr, prefixlen, varlen, 
    2185             :                                                 terminator, termlen, dbprtype(db_vartype), table_column);
    2186         324 :         CHECK_CONN(FAIL);
    2187         324 :         CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);
    2188         648 :         DBPERROR_RETURN(db_vartype != 0 && !is_tds_type_valid(db_vartype), SYBEUDTY);
    2189         324 :         vartype = (TDS_SERVER_TYPE) db_vartype;
    2190             : 
    2191         324 :         if (dbproc->hostfileinfo != NULL) {
    2192           0 :                 dbperror(dbproc, SYBEBCPB, 0);
    2193           0 :                 return FAIL;
    2194             :         }
    2195             : 
    2196         324 :         if (dbproc->bcpinfo->direction != DB_IN) {
    2197           0 :                 dbperror(dbproc, SYBEBCPN, 0);
    2198           0 :                 return FAIL;
    2199             :         }
    2200             : 
    2201         324 :         if (varlen < -1) {
    2202           0 :                 dbperror(dbproc, SYBEBCVLEN, 0);
    2203           0 :                 return FAIL;
    2204             :         }
    2205             : 
    2206         324 :         if (prefixlen != 0 && prefixlen != 1 && prefixlen != 2 && prefixlen != 4) {
    2207           0 :                 dbperror(dbproc, SYBEBCBPREF, 0);
    2208           0 :                 return FAIL;
    2209             :         }
    2210             : 
    2211         324 :         if (prefixlen == 0 && varlen == -1 && termlen == -1 && !is_fixed_type(vartype)) {
    2212           0 :                 tdsdump_log(TDS_DBG_FUNC, "bcp_bind(): non-fixed type %d requires prefix or terminator\n", vartype);
    2213             :                 return FAIL;
    2214             :         }
    2215             : 
    2216         324 :         if (is_fixed_type(vartype) && (varlen != -1 && varlen != 0)) {
    2217           0 :                 dbperror(dbproc, SYBEBCIT, 0);
    2218           0 :                 return FAIL;
    2219             :         }
    2220             : 
    2221         324 :         if (table_column <= 0 ||  table_column > dbproc->bcpinfo->bindinfo->num_cols) {
    2222           0 :                 dbperror(dbproc, SYBECNOR, 0);
    2223           0 :                 return FAIL;
    2224             :         }
    2225             :         
    2226         324 :         if (varaddr == NULL && (prefixlen != 0 || termlen != 0)) {
    2227           0 :                 dbperror(dbproc, SYBEBCBNPR, 0);
    2228           0 :                 return FAIL;
    2229             :         }
    2230             : 
    2231         324 :         colinfo = dbproc->bcpinfo->bindinfo->columns[table_column - 1];
    2232             : 
    2233             :         /* If varaddr is NULL and varlen greater than 0, the table column type must be SYBTEXT or SYBIMAGE 
    2234             :                 and the program variable type must be SYBTEXT, SYBCHAR, SYBIMAGE or SYBBINARY */
    2235         324 :         if (varaddr == NULL && varlen > 0) {
    2236           0 :                 int fOK = (colinfo->column_type == SYBTEXT || colinfo->column_type == SYBIMAGE) &&
    2237           0 :                           (vartype == SYBTEXT || vartype == SYBCHAR || vartype == SYBIMAGE || vartype == SYBBINARY );
    2238             :                 if( !fOK ) {
    2239           0 :                         dbperror(dbproc, SYBEBCBNTYP, 0);
    2240           0 :                         tdsdump_log(TDS_DBG_FUNC, "bcp_bind: SYBEBCBNTYP: column=%d and vartype=%d (should fail?)\n", 
    2241             :                                                         colinfo->column_type, vartype);
    2242             :                         /* return FAIL; */
    2243             :                 }
    2244             :         }
    2245             : 
    2246         324 :         colinfo->column_varaddr  = (char *)varaddr;
    2247         324 :         colinfo->column_bindtype = vartype;
    2248         324 :         colinfo->column_bindlen  = varlen;
    2249         324 :         colinfo->bcp_prefix_len = prefixlen;
    2250             : 
    2251         324 :         TDS_ZERO_FREE(colinfo->bcp_terminator);
    2252         324 :         colinfo->bcp_term_len = 0;
    2253         324 :         if (termlen > 0) {
    2254          54 :                 if ((colinfo->bcp_terminator =  tds_new(TDS_CHAR, termlen)) == NULL) {
    2255           0 :                         dbperror(dbproc, SYBEMEM, errno);
    2256           0 :                         return FAIL;
    2257             :                 }
    2258          54 :                 memcpy(colinfo->bcp_terminator, terminator, termlen);
    2259          54 :                 colinfo->bcp_term_len = termlen;
    2260             :         }
    2261             : 
    2262             :         return SUCCEED;
    2263             : }
    2264             : 
    2265             : static void
    2266           0 : _bcp_null_error(TDSBCPINFO *bcpinfo, int index TDS_UNUSED, int offset TDS_UNUSED)
    2267             : {
    2268           0 :         DBPROCESS *dbproc = (DBPROCESS *) bcpinfo->parent;
    2269           0 :         dbperror(dbproc, SYBEBCNN, 0);
    2270           0 : }
    2271             : 
    2272             : /** 
    2273             :  * \ingroup dblib_bcp_internal
    2274             :  * \brief For a bcp in from program variables, get the data from the host variable
    2275             :  *
    2276             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    2277             :  * \param bindcol 
    2278             :  * 
    2279             :  * \return TDS_SUCCESS or TDS_FAIL.
    2280             :  * \sa  _bcp_add_fixed_columns, _bcp_add_variable_columns, _bcp_send_bcp_record
    2281             :  */
    2282             : static TDSRET
    2283        4138 : _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int index TDS_UNUSED, int offset TDS_UNUSED)
    2284             : {
    2285             :         TDS_SERVER_TYPE coltype, desttype;
    2286             :         int collen;
    2287             :         int bytes_read;
    2288             :         BYTE *dataptr;
    2289        4138 :         DBPROCESS *dbproc = (DBPROCESS *) bcpinfo->parent;
    2290             :         TDSRET rc;
    2291             : 
    2292        4138 :         tdsdump_log(TDS_DBG_FUNC, "_bcp_get_col_data(%p, %p)\n", bcpinfo, bindcol);
    2293        4138 :         CHECK_CONN(TDS_FAIL);
    2294        4138 :         CHECK_NULP(bindcol, "_bcp_get_col_data", 2, TDS_FAIL);
    2295             : 
    2296        4138 :         dataptr = (BYTE *) bindcol->column_varaddr;
    2297             : 
    2298        4138 :         collen = 0;
    2299             : 
    2300             :         /* If a prefix length specified, read the correct  amount of data. */
    2301             : 
    2302        4138 :         if (bindcol->bcp_prefix_len > 0) {
    2303             : 
    2304           0 :                 switch (bindcol->bcp_prefix_len) {
    2305           0 :                 case 1:
    2306           0 :                         collen = TDS_GET_UA1(dataptr);
    2307           0 :                         dataptr += 1;
    2308           0 :                         break;
    2309           0 :                 case 2:
    2310           0 :                         collen = (TDS_SMALLINT) TDS_GET_UA2(dataptr);
    2311           0 :                         dataptr += 2;
    2312           0 :                         break;
    2313           0 :                 case 4:
    2314           0 :                         collen = (TDS_INT) TDS_GET_UA4(dataptr);
    2315           0 :                         dataptr += 4;
    2316           0 :                         break;
    2317             :                 }
    2318           0 :                 if (collen <= 0)
    2319             :                         goto null_data;
    2320             :         }
    2321             : 
    2322             :         /* if (Max) column length specified take that into consideration. */
    2323             : 
    2324        4138 :         if (bindcol->column_bindlen >= 0) {
    2325        2800 :                 if (bindcol->column_bindlen == 0)
    2326             :                         goto null_data;
    2327        1500 :                 if (collen)
    2328           0 :                         collen = TDS_MIN(bindcol->column_bindlen, collen);
    2329             :                 else
    2330             :                         collen = bindcol->column_bindlen;
    2331             :         }
    2332             : 
    2333        2838 :         desttype = tds_get_conversion_type(bindcol->column_type, bindcol->column_size);
    2334             : 
    2335        2838 :         coltype = bindcol->column_bindtype == 0 ? desttype : (TDS_SERVER_TYPE) bindcol->column_bindtype;
    2336             : 
    2337             :         /* Fixed Length data - this overrides anything else specified */
    2338        2838 :         if (is_fixed_type(coltype))
    2339         750 :                 collen = tds_get_size_by_type(coltype);
    2340             : 
    2341             :         /* read the data, finally */
    2342             : 
    2343        2838 :         if (bindcol->bcp_term_len > 0) {  /* terminated field */
    2344          88 :                 bytes_read = _bcp_get_term_var(dataptr, (BYTE *)bindcol->bcp_terminator, bindcol->bcp_term_len);
    2345             : 
    2346          88 :                 if (collen <= 0 || bytes_read < collen)
    2347          88 :                         collen = bytes_read;
    2348             : 
    2349          88 :                 if (collen == 0)
    2350             :                         goto null_data;
    2351             :         }
    2352             : 
    2353        2810 :         if (collen < 0)
    2354           0 :                 collen = (int) strlen((char *) dataptr);
    2355             : 
    2356        2810 :         rc = _bcp_convert_in(dbproc, coltype, (const TDS_CHAR *) dataptr, collen, desttype, bindcol);
    2357        2810 :         if (TDS_FAILED(rc))
    2358             :                 return rc;
    2359        2810 :         rtrim_bcpcol(bindcol);
    2360             : 
    2361        2810 :         return TDS_SUCCESS;
    2362             : 
    2363        1328 : null_data:
    2364        1328 :         bindcol->bcp_column_data->datalen = 0;
    2365        1328 :         bindcol->bcp_column_data->is_null = true;
    2366        1328 :         return TDS_SUCCESS;
    2367             : }
    2368             : 
    2369             : /**
    2370             :  * Function to read data from file. In this case is empty as data
    2371             :  * are already on bcp_column_data
    2372             :  */
    2373             : static TDSRET
    2374        2242 : _bcp_no_get_col_data(TDSBCPINFO *bcpinfo TDS_UNUSED, TDSCOLUMN *bindcol TDS_UNUSED, int index TDS_UNUSED, int offset TDS_UNUSED)
    2375             : {
    2376        2242 :         return TDS_SUCCESS;
    2377             : }
    2378             : 
    2379             : /**
    2380             :  * Get the data for bcp-in from program variables, where the program data
    2381             :  * have been identified as character terminated,  
    2382             :  * This is a low-level, internal function.  Call it correctly.  
    2383             :  */
    2384             : /** 
    2385             :  * \ingroup dblib_bcp_internal
    2386             :  * \brief 
    2387             :  *
    2388             :  * \param pdata 
    2389             :  * \param term 
    2390             :  * \param term_len 
    2391             :  * 
    2392             :  * \return data length.
    2393             :  */
    2394             : static int
    2395          88 : _bcp_get_term_var(const BYTE * pdata, const BYTE * term, int term_len)
    2396             : {
    2397             :         int bufpos;
    2398             : 
    2399          88 :         assert(term_len > 0);
    2400             : 
    2401             :         /* if bufpos becomes negative, we probably failed to find the terminator */
    2402         330 :         for (bufpos = 0; bufpos >= 0 && memcmp(pdata, term, term_len) != 0; pdata++) {
    2403         330 :                 bufpos++;
    2404             :         }
    2405             :         
    2406             :         assert(bufpos >= 0);
    2407          88 :         return bufpos;
    2408             : }
    2409             : 
    2410             : /** 
    2411             :  * \ingroup dblib_bcp_internal
    2412             :  * \brief trim a string of trailing blanks 
    2413             :  *
    2414             :  *      Replaces spaces at the end of a string with NULs
    2415             :  * \param str pointer to a character buffer (not null-terminated)
    2416             :  * \param len size of the \a str in bytes 
    2417             :  * 
    2418             :  * \return modified length
    2419             :  */
    2420             : static int
    2421             : rtrim(char *str, int len)
    2422             : {
    2423        1252 :         char *p = str + len - 1;
    2424             : 
    2425        1756 :         while (p > str && *p == ' ') {
    2426         504 :                 *p-- = '\0';
    2427             :         }
    2428        1252 :         return (int)(1 + p - str);
    2429             : }
    2430             : 
    2431             : static int
    2432             : rtrim_u16(uint16_t *str, int len, uint16_t space)
    2433             : {
    2434          62 :         uint16_t *p = str + len / 2 - 1;
    2435             : 
    2436          62 :         while (p > str && *p == space) {
    2437           0 :                 *p-- = '\0';
    2438             :         }
    2439          62 :         return (int)(1 + p - str) * 2;
    2440             : }
    2441             : 
    2442             : /** 
    2443             :  * \ingroup dblib_bcp_internal
    2444             :  * \brief 
    2445             :  *
    2446             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    2447             :  */
    2448             : static void
    2449        1196 : _bcp_free_columns(DBPROCESS * dbproc)
    2450             : {
    2451             :         int i;
    2452             : 
    2453        1196 :         tdsdump_log(TDS_DBG_FUNC, "_bcp_free_columns(%p)\n", dbproc);
    2454        1196 :         assert(dbproc && dbproc->hostfileinfo);
    2455             : 
    2456        1196 :         if (dbproc->hostfileinfo->host_columns) {
    2457        4038 :                 for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {
    2458        4038 :                         TDS_ZERO_FREE(dbproc->hostfileinfo->host_columns[i]->terminator);
    2459        4038 :                         TDS_ZERO_FREE(dbproc->hostfileinfo->host_columns[i]);
    2460             :                 }
    2461         794 :                 TDS_ZERO_FREE(dbproc->hostfileinfo->host_columns);
    2462         794 :                 dbproc->hostfileinfo->host_colcount = 0;
    2463             :         }
    2464        1196 : }
    2465             : 
    2466             : /** 
    2467             :  * \ingroup dblib_bcp_internal
    2468             :  * \brief 
    2469             :  *
    2470             :  * \param dbproc contains all information needed by db-lib to manage communications with the server.
    2471             :  * 
    2472             :  * \sa  bcp_done(), bcp_exec(), bcp_init()
    2473             :  */
    2474             : static void
    2475         862 : _bcp_free_storage(DBPROCESS * dbproc)
    2476             : {
    2477         862 :         tdsdump_log(TDS_DBG_FUNC, "_bcp_free_storage(%p)\n", dbproc);
    2478         862 :         assert(dbproc);
    2479             : 
    2480         862 :         if (dbproc->hostfileinfo) {
    2481         402 :                 TDS_ZERO_FREE(dbproc->hostfileinfo->hostfile);
    2482         402 :                 TDS_ZERO_FREE(dbproc->hostfileinfo->errorfile);
    2483         402 :                 _bcp_free_columns(dbproc);
    2484         402 :                 TDS_ZERO_FREE(dbproc->hostfileinfo);
    2485             :         }
    2486             : 
    2487         862 :         tds_free_bcpinfo(dbproc->bcpinfo);
    2488         862 :         dbproc->bcpinfo = NULL;
    2489         862 : }
    2490             : 
    2491             : /** Fast strftime for default bcp format */
    2492             : static int
    2493          80 : _bcp_strftime(char *buf, size_t maxsize, const char *format, const TDSDATEREC *dr, int prec)
    2494             : {
    2495          80 :         char *pbuf = buf;
    2496             : 
    2497          80 :         if (format)
    2498           0 :                 return (int) tds_strftime(pbuf, maxsize, format, dr, prec);
    2499             : 
    2500          80 :         pbuf += tds_u32toa_fast(pbuf, dr->year);
    2501             : 
    2502             :         /* The following "& 63" are to avoid overflows if values are corrupted */
    2503             : 
    2504          80 :         *pbuf++ = '-';
    2505          80 :         tds_02d_fast(pbuf, (dr->month + 1) & 63);
    2506          80 :         pbuf += 2;
    2507             : 
    2508          80 :         *pbuf++ = '-';
    2509          80 :         tds_02d_fast(pbuf, dr->day & 63);
    2510          80 :         pbuf += 2;
    2511             : 
    2512          80 :         *pbuf++ = ' ';
    2513          80 :         tds_02d_fast(pbuf, dr->hour & 63);
    2514          80 :         pbuf += 2;
    2515             : 
    2516          80 :         *pbuf++ = ':';
    2517          80 :         tds_02d_fast(pbuf, dr->minute & 63);
    2518          80 :         pbuf += 2;
    2519             : 
    2520          80 :         *pbuf++ = ':';
    2521          80 :         tds_02d_fast(pbuf, dr->second & 63);
    2522          80 :         pbuf += 2;
    2523             : 
    2524          80 :         if (prec > 0) {
    2525             :                 char ibuf[10];
    2526             : 
    2527          80 :                 *pbuf++ = '.';
    2528             : 
    2529          80 :                 memset(ibuf, '0', sizeof(ibuf));
    2530             :                 /* Mask off a negative sign (input should not contain this anyway) */
    2531          80 :                 tds_u32toa_fast_right(ibuf, dr->decimicrosecond & 0x7FFFFFFF);
    2532             :                 /* Skip first 3 digits here, as decimicrosecond should not exceed 9,999,999 */
    2533          80 :                 memcpy(pbuf, ibuf + 3, prec);
    2534          80 :                 pbuf += prec;
    2535             :         }
    2536          80 :         *pbuf = '\0';
    2537             : 
    2538             : #if ENABLE_EXTRA_CHECKS
    2539             :         {
    2540             :                 char tbuf[256];
    2541             : 
    2542          80 :                 tds_strftime(tbuf, sizeof(tbuf), BCP_DEFAULT_DATEFMT, dr, prec);
    2543          80 :                 if (strcmp(tbuf, (char *) buf)) {
    2544           0 :                         fprintf(stderr, "_bcp_strftime(%s) does not match tds_strftime(%s)\n", tbuf, (char *) buf);
    2545           0 :                         tds_extra_assert(!"_bcp_strftime mismatch");
    2546             :                 }
    2547             :         }
    2548             : #endif
    2549          80 :         return (int) (pbuf - buf);
    2550             : }

Generated by: LCOV version 1.13