LCOV - code coverage report
Current view: top level - src/odbc - bcp.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 148 251 59.0 %
Date: 2024-03-23 09:12:27 Functions: 9 12 75.0 %

          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/iconv.h>
      45             : #include <freetds/convert.h>
      46             : #include <freetds/odbc.h>
      47             : #include <freetds/utils/string.h>
      48             : #define TDSODBC_BCP
      49             : #include <odbcss.h>
      50             : 
      51             : static TDSRET
      52             : _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int offset);
      53             : static SQLLEN
      54             : _bcp_get_term_var(const TDS_CHAR * pdata, const TDS_CHAR * term, int term_len);
      55             : 
      56             : #define ODBCBCP_ERROR_RETURN(code) \
      57             :         do {odbc_errs_add(&dbc->errs, code, NULL); return;} while(0)
      58             : 
      59             : #define ODBCBCP_ERROR_DBINT(code) \
      60             :         do {odbc_errs_add(&dbc->errs, code, NULL); return -1;} while(0)
      61             : 
      62             : /**
      63             :  * \ingroup odbc_bcp
      64             :  * \brief Prepare for bulk copy operation on a table
      65             :  *
      66             :  * \param dbc ODBC database connection object
      67             :  * \param tblname the name of the table receiving or providing the data.
      68             :  * \param hfile the data file opposite the table, if any. NB: The current
      69             :  *              implementation does not support file I/O so this must be NULL
      70             :  * \param errfile the "error file" captures messages and, if errors are
      71             :  *              encountered. NB: The current implementation does not support
      72             :  *              file I/O so this must be NULL
      73             :  * \param direction one of
      74             :  *      - \b DB_IN writing to the table
      75             :  *      - \b DB_OUT writing to the host file (Not currently supported)
      76             :  *      .
      77             :  * \remarks bcp_init() sets the host file data format and acquires the table metadata.
      78             :  *      It is called before the other bulk copy functions.
      79             :  *
      80             :  *      The ODBC BCP functionality should be accessed via the inline functions in
      81             :  *      odbcss.h.
      82             :  *
      83             :  *      After calling this function, call bcp_bind() to associate your data with
      84             :  *      the appropriate table column.
      85             :  *
      86             :  * \sa  SQL_COPT_SS_BCP, odbc_bcp_bind(), odbc_bcp_done(), odbc_bcp_exec()
      87             :  */
      88             : void
      89          18 : odbc_bcp_init(TDS_DBC *dbc, const ODBC_CHAR *tblname, const ODBC_CHAR *hfile,
      90             :               const ODBC_CHAR *errfile, int direction _WIDE)
      91             : {
      92          18 :         if (TDS_UNLIKELY(tds_write_dump)) {
      93             : #ifdef ENABLE_ODBC_WIDE
      94           0 :                 if (wide) {
      95           0 :                         SQLWSTR_BUFS(3);
      96           0 :                         tdsdump_log(TDS_DBG_FUNC, "bcp_initW(%p, %ls, %ls, %ls, %d)\n",
      97           0 :                                     dbc, SQLWSTR(tblname->wide), SQLWSTR(hfile->wide), SQLWSTR(errfile->wide), direction);
      98           0 :                         SQLWSTR_FREE();
      99             :                 } else {
     100             : #else
     101             :                 {
     102             : #endif
     103           0 :                         tdsdump_log(TDS_DBG_FUNC, "bcp_init(%p, %s, %s, %s, %d)\n",
     104             :                                     dbc, (const char*) tblname, (const char*) hfile, (const char*) errfile, direction);
     105             :                 }
     106             :         }
     107          18 :         if (!tblname)
     108           0 :                 ODBCBCP_ERROR_RETURN("HY009");
     109             : 
     110             :         /* Free previously allocated storage in dbproc & initialise flags, etc. */
     111             : 
     112          18 :         odbc_bcp_free_storage(dbc);
     113             : 
     114             :         /*
     115             :          * Validate other parameters
     116             :          */
     117          18 :         if (dbc->tds_socket->conn->tds_version < 0x500)
     118           0 :                 ODBCBCP_ERROR_RETURN("HYC00");
     119             : 
     120          18 :         if (direction != BCP_DIRECTION_IN || hfile || errfile)
     121           0 :                 ODBCBCP_ERROR_RETURN("HYC00");
     122             : 
     123             :         /* Allocate storage */
     124             : 
     125          18 :         dbc->bcpinfo = tds_alloc_bcpinfo();
     126          18 :         if (dbc->bcpinfo == NULL)
     127           0 :                 ODBCBCP_ERROR_RETURN("HY001");
     128             : 
     129          18 :         if (!odbc_dstr_copy(dbc, &dbc->bcpinfo->tablename, SQL_NTS, tblname)) {
     130           0 :                 odbc_bcp_free_storage(dbc);
     131           0 :                 ODBCBCP_ERROR_RETURN("HY001");
     132             :         }
     133             : 
     134          36 :         if (tds_dstr_len(&dbc->bcpinfo->tablename) > 92 && !IS_TDS7_PLUS(dbc->tds_socket->conn)) {   /* 30.30.30 */
     135           0 :                 odbc_bcp_free_storage(dbc);
     136           0 :                 ODBCBCP_ERROR_RETURN("HYC00");
     137             :         }
     138             : 
     139          18 :         dbc->bcpinfo->direction = direction;
     140             : 
     141          18 :         dbc->bcpinfo->xfer_init  = 0;
     142          18 :         dbc->bcpinfo->bind_count = 0;
     143             : 
     144          18 :         if (TDS_FAILED(tds_bcp_init(dbc->tds_socket, dbc->bcpinfo))) {
     145             :                 /* TODO return proper error */
     146             :                 /* Attempt to use Bulk Copy with a non-existent Server table (might be why ...) */
     147           0 :                 ODBCBCP_ERROR_RETURN("HY000");
     148             :         }
     149             : }
     150             : 
     151             : 
     152             : /**
     153             :  * \ingroup odbc_bcp
     154             :  * \brief Set BCP options for data transfer
     155             :  *
     156             :  * \param dbc ODBC database connection object
     157             :  * \param field symbolic constant indicating the option to be set, one of:
     158             :  *              - \b BCPKEEPIDENTITY Enable identity insert, as if by executing
     159             :  *                'SET IDENTITY_INSERT \a table ON'. The default is off
     160             :  *              - \b BCPHINTS Arbitrary extra text to pass to the server. See the
     161             :  *                documentation for the bcp command-line tool which came with your
     162             :  *                database server for the correct syntax.
     163             :  * \param value The value for \a field.
     164             :  *
     165             :  * \remarks These options control the behavior of bcp_sendrow().
     166             :  *
     167             :  * \sa  odbc_bcp_batch(), odbc_bcp_init(), odbc_bcp_done()
     168             :  */
     169             : void
     170           0 : odbc_bcp_control(TDS_DBC *dbc, int field, void *value)
     171             : {
     172           0 :         tdsdump_log(TDS_DBG_FUNC, "bcp_control(%p, %d, %p)\n", dbc, field, value);
     173           0 :         if (dbc->bcpinfo == NULL)
     174           0 :                 ODBCBCP_ERROR_RETURN("HY010");
     175             : 
     176             : 
     177           0 :         switch (field) {
     178           0 :         case BCPKEEPIDENTITY:
     179           0 :                 dbc->bcpinfo->identity_insert_on = (value != NULL);
     180           0 :                 break;
     181           0 :         case BCPHINTS:
     182           0 :                 if (!value)
     183           0 :                         ODBCBCP_ERROR_RETURN("HY009");
     184           0 :                 dbc->bcphint = strdup((char*)value);
     185           0 :                 dbc->bcpinfo->hint = dbc->bcphint;
     186           0 :                 break;
     187           0 :         default:
     188           0 :                 ODBCBCP_ERROR_RETURN("HY009");
     189             :         }
     190             : }
     191             : 
     192             : /**
     193             :  * \ingroup odbc_bcp
     194             :  * \brief Override bcp_bind() by pointing to a different host variable.
     195             :  *
     196             :  * \param dbc ODBC database connection object
     197             :  * \param colptr The pointer, the address of your variable.
     198             :  * \param table_column The 1-based column ordinal in the table.
     199             :  * \remarks Use between calls to bcp_sendrow().  After calling bcp_colptr(),
     200             :  *              subsequent calls to bcp_sendrow() will bind to the new address.
     201             :  * \sa  odbc_bcp_bind(), odbc_bcp_sendrow()
     202             :  */
     203             : void
     204           0 : odbc_bcp_colptr(TDS_DBC *dbc, const void * colptr, int table_column)
     205             : {
     206             :         TDSCOLUMN *curcol;
     207             : 
     208           0 :         tdsdump_log(TDS_DBG_FUNC, "bcp_colptr(%p, %p, %d)\n", dbc, colptr, table_column);
     209           0 :         if (dbc->bcpinfo == NULL || dbc->bcpinfo->bindinfo == NULL)
     210           0 :                 ODBCBCP_ERROR_RETURN("HY010");
     211             :         /* colptr can be NULL */
     212             : 
     213           0 :         if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
     214           0 :                 ODBCBCP_ERROR_RETURN("HY010");
     215           0 :         if (table_column <= 0 || table_column > dbc->bcpinfo->bindinfo->num_cols)
     216           0 :                 ODBCBCP_ERROR_RETURN("HY009");
     217             : 
     218           0 :         curcol = dbc->bcpinfo->bindinfo->columns[table_column - 1];
     219           0 :         curcol->column_varaddr = (TDS_CHAR *)colptr;
     220             : }
     221             : 
     222             : 
     223             : /**
     224             :  * \ingroup odbc_bcp
     225             :  * \brief Write data in host variables to the table.
     226             :  *
     227             :  * \param dbc ODBC database connection object
     228             :  *
     229             :  * \remarks Call bcp_bind() first to describe the variables to be used.
     230             :  *      Use bcp_batch() to commit sets of rows.
     231             :  *      After sending the last row call bcp_done().
     232             :  * \sa  odbc_bcp_batch(), odbc_bcp_bind(), odbc_bcp_colptr(), odbc_bcp_done(),
     233             :  *      odbc_bcp_init()
     234             :  */
     235             : void
     236         162 : odbc_bcp_sendrow(TDS_DBC *dbc)
     237             : {
     238             :         TDSSOCKET *tds;
     239             : 
     240         162 :         tdsdump_log(TDS_DBG_FUNC, "bcp_sendrow(%p)\n", dbc);
     241         162 :         if (dbc->bcpinfo == NULL)
     242           0 :                 ODBCBCP_ERROR_RETURN("HY010");
     243             : 
     244         162 :         tds = dbc->tds_socket;
     245             : 
     246         162 :         if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
     247           0 :                 ODBCBCP_ERROR_RETURN("HY010");
     248             : 
     249             :         /*
     250             :          * The first time sendrow is called after bcp_init,
     251             :          * there is a certain amount of initialisation to be done.
     252             :          */
     253         162 :         if (dbc->bcpinfo->xfer_init == 0) {
     254             : 
     255             :                 /* The start_copy function retrieves details of the table's columns */
     256          18 :                 if (TDS_FAILED(tds_bcp_start_copy_in(tds, dbc->bcpinfo)))
     257           0 :                         ODBCBCP_ERROR_RETURN("HY000");
     258             : 
     259          18 :                 dbc->bcpinfo->xfer_init = 1;
     260             :         }
     261             : 
     262         162 :         dbc->bcpinfo->parent = dbc;
     263         162 :         if (TDS_FAILED(tds_bcp_send_record(dbc->tds_socket, dbc->bcpinfo, _bcp_get_col_data, NULL, 0)))
     264           0 :                 ODBCBCP_ERROR_RETURN("HY000");
     265             : }
     266             : 
     267             : 
     268             : /**
     269             :  * \ingroup odbc_bcp
     270             :  * \brief Commit a set of rows to the table.
     271             :  *
     272             :  * \param dbc ODBC database connection object
     273             :  * \remarks If not called, bcp_done() will cause the rows to be saved.
     274             :  * \return Count of rows saved, or -1 on error.
     275             :  * \sa  odbc_bcp_bind(), odbc_bcp_done(), odbc_bcp_sendrow()
     276             :  */
     277             : int
     278          18 : odbc_bcp_batch(TDS_DBC *dbc)
     279             : {
     280          18 :         int rows_copied = 0;
     281             : 
     282          18 :         tdsdump_log(TDS_DBG_FUNC, "bcp_batch(%p)\n", dbc);
     283          18 :         if (dbc->bcpinfo == NULL)
     284           0 :                 ODBCBCP_ERROR_DBINT("HY010");
     285             : 
     286          18 :         if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied)))
     287           0 :                 ODBCBCP_ERROR_DBINT("HY000");
     288             : 
     289          18 :         tds_bcp_start(dbc->tds_socket, dbc->bcpinfo);
     290             : 
     291          18 :         return rows_copied;
     292             : }
     293             : 
     294             : /**
     295             :  * \ingroup odbc_bcp
     296             :  * \brief Conclude the transfer of data from program variables.
     297             :  *
     298             :  * \param dbc ODBC database connection object
     299             :  * \remarks Do not overlook this function.  According to Sybase, failure to call bcp_done()
     300             :  * "will result in unpredictable errors".
     301             :  * \return As with bcp_batch(), the count of rows saved, or -1 on error.
     302             :  * \sa  bcp_batch(), bcp_bind(), bcp_moretext(), bcp_sendrow()
     303             :  */
     304             : int
     305          18 : odbc_bcp_done(TDS_DBC *dbc)
     306             : {
     307             :         int rows_copied;
     308             : 
     309          18 :         tdsdump_log(TDS_DBG_FUNC, "bcp_done(%p)\n", dbc);
     310             : 
     311          18 :         if (!(dbc->bcpinfo))
     312           0 :                 ODBCBCP_ERROR_DBINT("HY010");
     313             : 
     314          18 :         if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied)))
     315           0 :                 ODBCBCP_ERROR_DBINT("HY000");
     316             : 
     317          18 :         odbc_bcp_free_storage(dbc);
     318             : 
     319          18 :         return rows_copied;
     320             : }
     321             : 
     322             : /**
     323             :  * \ingroup odbc_bcp
     324             :  * \brief Bind a program host variable to a database column
     325             :  *
     326             :  * \param dbc ODBC database connection object
     327             :  * \param varaddr address of host variable
     328             :  * \param prefixlen length of any prefix found at the beginning of \a varaddr, in bytes.
     329             :  *      Use zero for fixed-length datatypes.
     330             :  * \param varlen bytes of data in \a varaddr.  Zero for NULL, -1 for fixed-length datatypes.
     331             :  * \param terminator byte sequence that marks the end of the data in \a varaddr
     332             :  * \param termlen length of \a terminator
     333             :  * \param vartype datatype of the host variable
     334             :  * \param table_column Nth column, starting at 1, in the table.
     335             :  *
     336             :  * \remarks The order of operation is:
     337             :  *      - bcp_init() with \a hfile == NULL and \a direction == DB_IN.
     338             :  *      - bcp_bind(), once per column you want to write to
     339             :  *      - bcp_batch(), optionally, to commit a set of rows
     340             :  *      - bcp_done()
     341             :  *
     342             :  * \sa  odbc_bcp_batch(), odbc_bcp_done(), odbc_bcp_sendrow()
     343             :  */
     344             : void
     345         476 : odbc_bcp_bind(TDS_DBC *dbc, const void * varaddr, int prefixlen, int varlen,
     346             :          const void * terminator, int termlen, int vartype, int table_column)
     347             : {
     348             :         TDSCOLUMN *colinfo;
     349             : 
     350         476 :         tdsdump_log(TDS_DBG_FUNC, "bcp_bind(%p, %p, %d, %d -- %p, %d, %d, %d)\n",
     351             :                                                 dbc, varaddr, prefixlen, varlen,
     352             :                                                 terminator, termlen, vartype, table_column);
     353         476 :         if (!dbc->bcpinfo)
     354           0 :                 ODBCBCP_ERROR_RETURN("HY010");
     355             : 
     356         476 :         if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
     357           0 :                 ODBCBCP_ERROR_RETURN("HY010");
     358             : 
     359         476 :         if (varlen < -1 && varlen != SQL_VARLEN_DATA)
     360           0 :                 ODBCBCP_ERROR_RETURN("HY009");
     361             : 
     362         476 :         if (prefixlen != 0 && prefixlen != 1 && prefixlen != 2 && prefixlen != 4 && prefixlen != 8)
     363           0 :                 ODBCBCP_ERROR_RETURN("HY009");
     364             : 
     365         952 :         if (vartype != 0 && !is_tds_type_valid(vartype))
     366           0 :                 ODBCBCP_ERROR_RETURN("HY004");
     367             : 
     368         476 :         if (prefixlen == 0 && varlen == SQL_VARLEN_DATA && termlen == -1 && !is_fixed_type(vartype)) {
     369           0 :                 tdsdump_log(TDS_DBG_FUNC, "bcp_bind(): non-fixed type %d requires prefix or terminator\n", vartype);
     370           0 :                 ODBCBCP_ERROR_RETURN("HY009");
     371             :         }
     372             : 
     373         476 :         if (table_column <= 0 ||  table_column > dbc->bcpinfo->bindinfo->num_cols)
     374           0 :                 ODBCBCP_ERROR_RETURN("HY009");
     375             : 
     376         476 :         if (varaddr == NULL && (prefixlen != 0 || termlen != 0))
     377           0 :                 ODBCBCP_ERROR_RETURN("HY009");
     378             : 
     379         476 :         colinfo = dbc->bcpinfo->bindinfo->columns[table_column - 1];
     380             : 
     381             :         /* If varaddr is NULL and varlen greater than 0, the table column type must be SYBTEXT or SYBIMAGE
     382             :                 and the program variable type must be SYBTEXT, SYBCHAR, SYBIMAGE or SYBBINARY */
     383         476 :         if (varaddr == NULL && varlen >= 0) {
     384           0 :                 int fOK = (colinfo->column_type == SYBTEXT || colinfo->column_type == SYBIMAGE) &&
     385           0 :                           (vartype == SYBTEXT || vartype == SYBCHAR || vartype == SYBIMAGE || vartype == SYBBINARY );
     386             :                 if( !fOK ) {
     387           0 :                         tdsdump_log(TDS_DBG_FUNC, "bcp_bind: SYBEBCBNTYP: column=%d and vartype=%d (should fail?)\n",
     388             :                                                         colinfo->column_type, vartype);
     389           0 :                         ODBCBCP_ERROR_RETURN("HY009");
     390             :                 }
     391             :         }
     392             : 
     393         476 :         colinfo->column_varaddr  = (char *)varaddr;
     394         476 :         colinfo->column_bindtype = vartype;
     395         476 :         colinfo->column_bindlen  = varlen;
     396         476 :         colinfo->bcp_prefix_len = prefixlen;
     397             : 
     398         476 :         TDS_ZERO_FREE(colinfo->bcp_terminator);
     399         476 :         colinfo->bcp_term_len = 0;
     400         476 :         if (termlen > 0) {
     401           0 :                 if ((colinfo->bcp_terminator =  tds_new(TDS_CHAR, termlen)) == NULL)
     402           0 :                         ODBCBCP_ERROR_RETURN("HY001");
     403           0 :                 memcpy(colinfo->bcp_terminator, terminator, termlen);
     404           0 :                 colinfo->bcp_term_len = termlen;
     405             :         }
     406             : }
     407             : 
     408             : static SQLLEN
     409         484 : _bcp_iconv_helper(const TDS_DBC *dbc, const TDSCOLUMN *bindcol, const TDS_CHAR * src, size_t srclen, char * dest, size_t destlen)
     410             : {
     411         484 :         if (bindcol->char_conv) {
     412         484 :                 char *orig_dest = dest;
     413             : 
     414         484 :                 if (tds_iconv(dbc->tds_socket, bindcol->char_conv, to_server, &src, &srclen, &dest, &destlen) == (size_t)-1)
     415             :                         return -1;
     416         484 :                 return dest - orig_dest;
     417             :         }
     418             : 
     419           0 :         if (destlen > srclen)
     420           0 :                 destlen = srclen;
     421           0 :         memcpy(dest, src, destlen);
     422           0 :         return destlen;
     423             : }
     424             : 
     425             : static SQLLEN
     426        2410 : _tdsodbc_dbconvert(TDS_DBC *dbc, int srctype, const TDS_CHAR * src, SQLLEN src_len,
     427             :                    int desttype, unsigned char * dest, TDSCOLUMN *bindcol)
     428             : {
     429             :         CONV_RESULT dres;
     430             :         SQLLEN ret;
     431             :         SQLLEN len;
     432        2410 :         SQLLEN destlen = bindcol->column_size;
     433             :         TDS_DATETIMEALL dta;
     434             :         TDS_NUMERIC num;
     435             :         SQL_NUMERIC_STRUCT * sql_num;
     436        2410 :         bool always_convert = false;
     437             : 
     438        2410 :         assert(src_len >= 0);
     439        2410 :         assert(src != NULL);
     440        2410 :         assert(dest != NULL);
     441        2410 :         assert(destlen > 0);
     442             : 
     443        2410 :         tdsdump_log(TDS_DBG_FUNC, "tdsodbc_dbconvert(%p, %d, %p, %d, %d, %p, %d)\n",
     444             :                         dbc, srctype, src, (int)src_len, desttype, dest, (int)destlen);
     445             : 
     446        2410 :         switch (srctype) {
     447           2 :         case SYBMSDATETIME2:
     448           2 :                 convert_datetime2server(SQL_C_TYPE_TIMESTAMP, src, &dta);
     449           2 :                 dta.time_prec = (destlen - 40) / 2;
     450           2 :                 src = (char *) &dta;
     451           2 :                 break;
     452           4 :         case SYBDECIMAL:
     453             :         case SYBNUMERIC:
     454           4 :                 sql_num = (SQL_NUMERIC_STRUCT *) src;
     455           4 :                 num.precision = sql_num->precision;
     456           4 :                 num.scale = sql_num->scale;
     457           4 :                 num.array[0] = sql_num->sign ^ 1;
     458             :                 /* test precision so client do not crash our library */
     459           4 :                 if (num.precision <= 0 || num.precision > 38 || num.scale > num.precision)
     460             :                         /* TODO add proper error */
     461             :                         return -1;
     462           4 :                 len = tds_numeric_bytes_per_prec[num.precision];
     463           4 :                 memcpy(num.array + 1, sql_num->val, len - 1);
     464           4 :                 tds_swap_bytes(num.array + 1, len - 1);
     465           4 :                 if (len < sizeof(num.array))
     466           4 :                         memset(num.array + len, 0, sizeof(num.array) - len);
     467           4 :                 src = (char *) &num;
     468           4 :                 always_convert = num.scale != bindcol->column_scale;
     469           4 :                 break;
     470             :                 /* TODO intervals */
     471             :         }
     472             : 
     473             :         /* oft times we are asked to convert a data type to itself */
     474        2410 :         if ((srctype == desttype || is_similar_type(srctype, desttype)) && !always_convert) {
     475         646 :                 if (is_char_type(desttype)) {
     476         482 :                         ret = _bcp_iconv_helper(dbc, bindcol, src, src_len, (char *)dest, destlen);
     477             :                 }
     478             :                 else {
     479         164 :                         ret = destlen < src_len ? destlen : src_len;
     480         164 :                         memcpy(dest, src, ret);
     481             :                 }
     482             :                 return ret;
     483             :         }
     484             : 
     485        1764 :         tdsdump_log(TDS_DBG_INFO1, "dbconvert() calling tds_convert\n");
     486             : 
     487        1764 :         if (is_numeric_type(desttype)) {
     488         322 :                 dres.n.precision = bindcol->column_prec;
     489         322 :                 dres.n.scale = bindcol->column_scale;
     490             :         }
     491        1764 :         len = tds_convert(dbc->env->tds_ctx, srctype, src, src_len, desttype, &dres);
     492        1764 :         tdsdump_log(TDS_DBG_INFO1, "dbconvert() called tds_convert returned %d\n", (int)len);
     493             : 
     494        1764 :         if (len < 0) {
     495           0 :                 odbc_convert_err_set(&dbc->errs, len);
     496           0 :                 return -1;
     497             :         }
     498             : 
     499        1764 :         switch (desttype) {
     500           0 :         case SYBBINARY:
     501             :         case SYBVARBINARY:
     502             :         case SYBIMAGE:
     503           0 :                 ret = destlen < len ? destlen : len;
     504           0 :                 memcpy(dest, dres.ib, ret);
     505           0 :                 free(dres.ib);
     506           0 :                 break;
     507        1762 :         case SYBINT1:
     508             :         case SYBINT2:
     509             :         case SYBINT4:
     510             :         case SYBINT8:
     511             :         case SYBFLT8:
     512             :         case SYBREAL:
     513             :         case SYBBIT:
     514             :         case SYBBITN:
     515             :         case SYBMONEY:
     516             :         case SYBMONEY4:
     517             :         case SYBDATETIME:
     518             :         case SYBDATETIME4:
     519             :         case SYBNUMERIC:
     520             :         case SYBDECIMAL:
     521             :         case SYBUNIQUE:
     522             :         case SYBMSDATE:
     523             :         case SYBMSTIME:
     524             :         case SYBMSDATETIME2:
     525             :         case SYBMSDATETIMEOFFSET:
     526        1762 :                 memcpy(dest, &dres, len);
     527        1762 :                 ret = len;
     528        1762 :                 break;
     529           2 :         case SYBCHAR:
     530             :         case SYBVARCHAR:
     531             :         case SYBTEXT:
     532           2 :                 ret = _bcp_iconv_helper(dbc, bindcol, dres.c, len, (char *)dest, destlen);
     533           2 :                 free(dres.c);
     534           2 :                 break;
     535           0 :         default:
     536           0 :                 tdsdump_log(TDS_DBG_INFO1, "error: dbconvert(): unrecognized desttype %d \n", desttype);
     537             :                 ret = -1;
     538             :                 break;
     539             : 
     540             :         }
     541             :         return (ret);
     542             : }
     543             : 
     544             : static TDSRET
     545        4652 : _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int offset)
     546             : {
     547             :         TDS_TINYINT ti;
     548             :         TDS_SMALLINT si;
     549             :         TDS_INT li;
     550             :         TDS_INT8 lli;
     551             :         TDS_SERVER_TYPE desttype, coltype;
     552             :         SQLLEN col_len;
     553             :         int data_is_null;
     554             :         SQLLEN bytes_read;
     555             :         int converted_data_size;
     556             :         TDS_CHAR *dataptr;
     557        4652 :         TDS_DBC *dbc = (TDS_DBC *) bcpinfo->parent;
     558             : 
     559        4652 :         tdsdump_log(TDS_DBG_FUNC, "_bcp_get_col_data(%p, %p)\n", bcpinfo, bindcol);
     560             : 
     561        4652 :         dataptr = bindcol->column_varaddr;
     562             : 
     563        4652 :         data_is_null = 0;
     564        4652 :         col_len = SQL_NULL_DATA;
     565             : 
     566             :         /* If a prefix length specified, read the correct  amount of data. */
     567             : 
     568        4652 :         if (bindcol->bcp_prefix_len > 0) {
     569             : 
     570        2320 :                 switch (bindcol->bcp_prefix_len) {
     571           0 :                 case 1:
     572           0 :                         memcpy(&ti, dataptr, 1);
     573           0 :                         dataptr += 1;
     574           0 :                         col_len = ti;
     575           0 :                         break;
     576           0 :                 case 2:
     577           0 :                         memcpy(&si, dataptr, 2);
     578           0 :                         dataptr += 2;
     579           0 :                         col_len = si;
     580           0 :                         break;
     581           0 :                 case 4:
     582           0 :                         memcpy(&li, dataptr, 4);
     583           0 :                         dataptr += 4;
     584           0 :                         col_len = li;
     585           0 :                         break;
     586        2320 :                 case 8:
     587        2320 :                         memcpy(&lli, dataptr, 8);
     588        2320 :                         dataptr += 8;
     589        2320 :                         col_len = lli;
     590             :                         if (lli != col_len)
     591             :                                 return TDS_FAIL;
     592             :                         break;
     593             :                 }
     594        2320 :                 if (col_len == SQL_NULL_DATA)
     595             :                         data_is_null = 1;
     596             :         }
     597             : 
     598             :         /* if (Max) column length specified take that into consideration. */
     599             : 
     600        4652 :         if (bindcol->column_bindlen == SQL_NULL_DATA)
     601             :                 data_is_null = 1;
     602        3530 :         else if (!data_is_null && bindcol->column_bindlen != SQL_VARLEN_DATA) {
     603        1770 :                 if (col_len != SQL_NULL_DATA)
     604         880 :                         col_len = ((TDS_INT8)bindcol->column_bindlen < col_len) ? bindcol->column_bindlen : col_len;
     605             :                 else
     606         890 :                         col_len = bindcol->column_bindlen;
     607             :         }
     608             : 
     609        4652 :         desttype = tds_get_conversion_type(bindcol->column_type, bindcol->column_size);
     610             : 
     611             :         /* Fixed Length data - this overrides anything else specified */
     612        4652 :         coltype = bindcol->column_bindtype == 0 ? desttype : (TDS_SERVER_TYPE) bindcol->column_bindtype;
     613        4652 :         if (is_fixed_type(coltype)) {
     614        1124 :                 col_len = tds_get_size_by_type(coltype);
     615             :         }
     616             : 
     617             :         /* read the data, finally */
     618             : 
     619        4652 :         if (!data_is_null && bindcol->bcp_term_len > 0) { /* terminated field */
     620           0 :                 bytes_read = _bcp_get_term_var(dataptr, bindcol->bcp_terminator, bindcol->bcp_term_len);
     621             : 
     622           0 :                 if (col_len != SQL_NULL_DATA)
     623           0 :                         col_len = (bytes_read < col_len) ? bytes_read : col_len;
     624             :                 else
     625             :                         col_len = bytes_read;
     626             :         }
     627             : 
     628        4652 :         if (data_is_null) {
     629        2242 :                 bindcol->bcp_column_data->datalen = 0;
     630        2242 :                 bindcol->bcp_column_data->is_null = true;
     631             :         } else {
     632        2410 :                 if ((converted_data_size =
     633        2410 :                      _tdsodbc_dbconvert(dbc, coltype,
     634             :                                dataptr, col_len,
     635        2410 :                                desttype, bindcol->bcp_column_data->data, bindcol)) == -1) {
     636             :                         return TDS_FAIL;
     637             :                 }
     638             : 
     639        2410 :                 bindcol->bcp_column_data->datalen = converted_data_size;
     640        2410 :                 bindcol->bcp_column_data->is_null = false;
     641             :         }
     642             : 
     643             :         return TDS_SUCCESS;
     644             : }
     645             : 
     646             : /**
     647             :  * Get the data for bcp-in from program variables, where the program data
     648             :  * have been identified as character terminated,
     649             :  * This is a low-level, internal function.  Call it correctly.
     650             :  */
     651             : static SQLLEN
     652           0 : _bcp_get_term_var(const TDS_CHAR * pdata, const TDS_CHAR * term, int term_len)
     653             : {
     654             :         SQLLEN bufpos;
     655             : 
     656           0 :         assert(term_len > 0);
     657             : 
     658           0 :         if (term_len == 1 && *term == '\0')  /* significant optimization for very common case */
     659           0 :                 return strlen(pdata);
     660             : 
     661             :         /* if bufpos becomes negative, we probably failed to find the terminator */
     662           0 :         for (bufpos = 0; bufpos >= 0 && memcmp(pdata, term, term_len) != 0; pdata++) {
     663           0 :                 bufpos++;
     664             :         }
     665             : 
     666             :         assert(bufpos >= 0);
     667             :         return bufpos;
     668             : }
     669             : 
     670             : void
     671         936 : odbc_bcp_free_storage(TDS_DBC *dbc)
     672             : {
     673         936 :         tdsdump_log(TDS_DBG_FUNC, "_bcp_free_storage(%p)\n", dbc);
     674         936 :         assert(dbc);
     675             : 
     676         936 :         tds_free_bcpinfo(dbc->bcpinfo);
     677         936 :         dbc->bcpinfo = NULL;
     678         936 :         TDS_ZERO_FREE(dbc->bcphint);
     679         936 : }
     680             : 

Generated by: LCOV version 1.13