LCOV - code coverage report
Current view: top level - src/odbc - bcp.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 155 256 60.5 %
Date: 2025-02-21 09:36:06 Functions: 10 12 83.3 %

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

Generated by: LCOV version 1.13