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-01-18 11:50:39 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          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           2 : odbc_bcp_control(TDS_DBC *dbc, int field, void *value)
     171             : {
     172             : #ifdef ENABLE_ODBC_WIDE
     173           2 :         int wide = 0;
     174             : #endif
     175             : 
     176           2 :         tdsdump_log(TDS_DBG_FUNC, "bcp_control(%p, %d, %p)\n", dbc, field, value);
     177           2 :         if (dbc->bcpinfo == NULL)
     178           0 :                 ODBCBCP_ERROR_RETURN("HY010");
     179             : 
     180             : 
     181           2 :         switch (field) {
     182           0 :         case BCPKEEPIDENTITY:
     183           0 :                 dbc->bcpinfo->identity_insert_on = (value != NULL);
     184           0 :                 break;
     185           2 :         case BCPHINTSA:
     186           2 :                 if (!value)
     187           0 :                         ODBCBCP_ERROR_RETURN("HY009");
     188           2 :                 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         162 : odbc_bcp_sendrow(TDS_DBC *dbc)
     250             : {
     251             :         TDSSOCKET *tds;
     252             : 
     253         162 :         tdsdump_log(TDS_DBG_FUNC, "bcp_sendrow(%p)\n", dbc);
     254         162 :         if (dbc->bcpinfo == NULL)
     255           0 :                 ODBCBCP_ERROR_RETURN("HY010");
     256             : 
     257         162 :         tds = dbc->tds_socket;
     258             : 
     259         162 :         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         162 :         if (dbc->bcpinfo->xfer_init == 0) {
     267             : 
     268             :                 /* The start_copy function retrieves details of the table's columns */
     269          18 :                 if (TDS_FAILED(tds_bcp_start_copy_in(tds, dbc->bcpinfo)))
     270           0 :                         ODBCBCP_ERROR_RETURN("HY000");
     271             : 
     272          18 :                 dbc->bcpinfo->xfer_init = 1;
     273             :         }
     274             : 
     275         162 :         dbc->bcpinfo->parent = dbc;
     276         162 :         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          18 : odbc_bcp_batch(TDS_DBC *dbc)
     292             : {
     293          18 :         int rows_copied = 0;
     294             : 
     295          18 :         tdsdump_log(TDS_DBG_FUNC, "bcp_batch(%p)\n", dbc);
     296          18 :         if (dbc->bcpinfo == NULL)
     297           0 :                 ODBCBCP_ERROR_DBINT("HY010");
     298             : 
     299          18 :         if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied)))
     300           0 :                 ODBCBCP_ERROR_DBINT("HY000");
     301             : 
     302          18 :         tds_bcp_start(dbc->tds_socket, dbc->bcpinfo);
     303             : 
     304          18 :         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          18 : odbc_bcp_done(TDS_DBC *dbc)
     319             : {
     320             :         int rows_copied;
     321             : 
     322          18 :         tdsdump_log(TDS_DBG_FUNC, "bcp_done(%p)\n", dbc);
     323             : 
     324          18 :         if (!(dbc->bcpinfo))
     325           0 :                 ODBCBCP_ERROR_DBINT("HY010");
     326             : 
     327          18 :         if (TDS_FAILED(tds_bcp_done(dbc->tds_socket, &rows_copied)))
     328           0 :                 ODBCBCP_ERROR_DBINT("HY000");
     329             : 
     330          18 :         odbc_bcp_free_storage(dbc);
     331             : 
     332          18 :         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         476 : 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         476 :         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         476 :         if (!dbc->bcpinfo)
     367           0 :                 ODBCBCP_ERROR_RETURN("HY010");
     368             : 
     369         476 :         if (dbc->bcpinfo->direction != BCP_DIRECTION_IN)
     370           0 :                 ODBCBCP_ERROR_RETURN("HY010");
     371             : 
     372         476 :         if (varlen < -1 && varlen != SQL_VARLEN_DATA)
     373           0 :                 ODBCBCP_ERROR_RETURN("HY009");
     374             : 
     375         476 :         if (prefixlen != 0 && prefixlen != 1 && prefixlen != 2 && prefixlen != 4 && prefixlen != 8)
     376           0 :                 ODBCBCP_ERROR_RETURN("HY009");
     377             : 
     378         952 :         if (vartype != 0 && !is_tds_type_valid(vartype))
     379           0 :                 ODBCBCP_ERROR_RETURN("HY004");
     380             : 
     381         476 :         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         476 :         if (table_column <= 0 ||  table_column > dbc->bcpinfo->bindinfo->num_cols)
     387           0 :                 ODBCBCP_ERROR_RETURN("HY009");
     388             : 
     389         476 :         if (varaddr == NULL && (prefixlen != 0 || termlen != 0))
     390           0 :                 ODBCBCP_ERROR_RETURN("HY009");
     391             : 
     392         476 :         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         476 :         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         476 :         colinfo->column_varaddr  = (char *)varaddr;
     407         476 :         colinfo->column_bindtype = vartype;
     408         476 :         colinfo->column_bindlen  = varlen;
     409         476 :         colinfo->bcp_prefix_len = prefixlen;
     410             : 
     411         476 :         TDS_ZERO_FREE(colinfo->bcp_terminator);
     412         476 :         colinfo->bcp_term_len = 0;
     413         476 :         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         484 : _bcp_iconv_helper(const TDS_DBC *dbc, const TDSCOLUMN *bindcol, const TDS_CHAR * src, size_t srclen, char * dest, size_t destlen)
     423             : {
     424         484 :         if (bindcol->char_conv) {
     425         484 :                 char *orig_dest = dest;
     426             : 
     427         484 :                 if (tds_iconv(dbc->tds_socket, bindcol->char_conv, to_server, &src, &srclen, &dest, &destlen) == (size_t)-1)
     428             :                         return -1;
     429         484 :                 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        2410 : _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        2410 :         SQLLEN destlen = bindcol->column_size;
     446             :         TDS_DATETIMEALL dta;
     447             :         TDS_NUMERIC num;
     448             :         SQL_NUMERIC_STRUCT * sql_num;
     449        2410 :         bool always_convert = false;
     450             : 
     451        2410 :         assert(src_len >= 0);
     452        2410 :         assert(src != NULL);
     453        2410 :         assert(dest != NULL);
     454        2410 :         assert(destlen > 0);
     455             : 
     456        2410 :         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        2410 :         switch (srctype) {
     460           2 :         case SYBMSDATETIME2:
     461           2 :                 convert_datetime2server(SQL_C_TYPE_TIMESTAMP, src, &dta);
     462           2 :                 dta.time_prec = (destlen - 40) / 2;
     463           2 :                 src = (char *) &dta;
     464           2 :                 break;
     465           4 :         case SYBDECIMAL:
     466             :         case SYBNUMERIC:
     467           4 :                 sql_num = (SQL_NUMERIC_STRUCT *) src;
     468           4 :                 num.precision = sql_num->precision;
     469           4 :                 num.scale = sql_num->scale;
     470           4 :                 num.array[0] = sql_num->sign ^ 1;
     471             :                 /* test precision so client do not crash our library */
     472           4 :                 if (num.precision <= 0 || num.precision > 38 || num.scale > num.precision)
     473             :                         /* TODO add proper error */
     474             :                         return -1;
     475           4 :                 len = tds_numeric_bytes_per_prec[num.precision];
     476           4 :                 memcpy(num.array + 1, sql_num->val, len - 1);
     477           4 :                 tds_swap_bytes(num.array + 1, len - 1);
     478           4 :                 if (len < sizeof(num.array))
     479           4 :                         memset(num.array + len, 0, sizeof(num.array) - len);
     480           4 :                 src = (char *) &num;
     481           4 :                 always_convert = num.scale != bindcol->column_scale;
     482           4 :                 break;
     483             :                 /* TODO intervals */
     484             :         }
     485             : 
     486             :         /* oft times we are asked to convert a data type to itself */
     487        2410 :         if ((srctype == desttype || is_similar_type(srctype, desttype)) && !always_convert) {
     488         646 :                 if (is_char_type(desttype)) {
     489         482 :                         ret = _bcp_iconv_helper(dbc, bindcol, src, src_len, (char *)dest, destlen);
     490             :                 }
     491             :                 else {
     492         164 :                         ret = destlen < src_len ? destlen : src_len;
     493         164 :                         memcpy(dest, src, ret);
     494             :                 }
     495             :                 return ret;
     496             :         }
     497             : 
     498        1764 :         tdsdump_log(TDS_DBG_INFO1, "dbconvert() calling tds_convert\n");
     499             : 
     500        1764 :         if (is_numeric_type(desttype)) {
     501         322 :                 dres.n.precision = bindcol->column_prec;
     502         322 :                 dres.n.scale = bindcol->column_scale;
     503             :         }
     504        1764 :         len = tds_convert(dbc->env->tds_ctx, srctype, src, src_len, desttype, &dres);
     505        1764 :         tdsdump_log(TDS_DBG_INFO1, "dbconvert() called tds_convert returned %d\n", (int)len);
     506             : 
     507        1764 :         if (len < 0) {
     508           0 :                 odbc_convert_err_set(&dbc->errs, len);
     509           0 :                 return -1;
     510             :         }
     511             : 
     512        1764 :         switch (desttype) {
     513           0 :         case SYBBINARY:
     514             :         case SYBVARBINARY:
     515             :         case SYBIMAGE:
     516           0 :                 ret = destlen < len ? destlen : len;
     517           0 :                 memcpy(dest, dres.ib, ret);
     518           0 :                 free(dres.ib);
     519           0 :                 break;
     520        1762 :         case SYBINT1:
     521             :         case SYBINT2:
     522             :         case SYBINT4:
     523             :         case SYBINT8:
     524             :         case SYBFLT8:
     525             :         case SYBREAL:
     526             :         case SYBBIT:
     527             :         case SYBBITN:
     528             :         case SYBMONEY:
     529             :         case SYBMONEY4:
     530             :         case SYBDATETIME:
     531             :         case SYBDATETIME4:
     532             :         case SYBNUMERIC:
     533             :         case SYBDECIMAL:
     534             :         case SYBUNIQUE:
     535             :         case SYBMSDATE:
     536             :         case SYBMSTIME:
     537             :         case SYBMSDATETIME2:
     538             :         case SYBMSDATETIMEOFFSET:
     539        1762 :                 memcpy(dest, &dres, len);
     540        1762 :                 ret = len;
     541        1762 :                 break;
     542           2 :         case SYBCHAR:
     543             :         case SYBVARCHAR:
     544             :         case SYBTEXT:
     545           2 :                 ret = _bcp_iconv_helper(dbc, bindcol, dres.c, len, (char *)dest, destlen);
     546           2 :                 free(dres.c);
     547           2 :                 break;
     548           0 :         default:
     549           0 :                 tdsdump_log(TDS_DBG_INFO1, "error: dbconvert(): unrecognized desttype %d \n", desttype);
     550             :                 ret = -1;
     551             :                 break;
     552             : 
     553             :         }
     554             :         return (ret);
     555             : }
     556             : 
     557             : static TDSRET
     558        4652 : _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int offset TDS_UNUSED)
     559             : {
     560             :         TDS_TINYINT ti;
     561             :         TDS_SMALLINT si;
     562             :         TDS_INT li;
     563             :         TDS_INT8 lli;
     564             :         TDS_SERVER_TYPE desttype, coltype;
     565             :         SQLLEN col_len;
     566             :         int data_is_null;
     567             :         SQLLEN bytes_read;
     568             :         int converted_data_size;
     569             :         TDS_CHAR *dataptr;
     570        4652 :         TDS_DBC *dbc = (TDS_DBC *) bcpinfo->parent;
     571             : 
     572        4652 :         tdsdump_log(TDS_DBG_FUNC, "_bcp_get_col_data(%p, %p)\n", bcpinfo, bindcol);
     573             : 
     574        4652 :         dataptr = bindcol->column_varaddr;
     575             : 
     576        4652 :         data_is_null = 0;
     577        4652 :         col_len = SQL_NULL_DATA;
     578             : 
     579             :         /* If a prefix length specified, read the correct  amount of data. */
     580             : 
     581        4652 :         if (bindcol->bcp_prefix_len > 0) {
     582             : 
     583        2320 :                 switch (bindcol->bcp_prefix_len) {
     584           0 :                 case 1:
     585           0 :                         memcpy(&ti, dataptr, 1);
     586           0 :                         dataptr += 1;
     587           0 :                         col_len = ti;
     588           0 :                         break;
     589           0 :                 case 2:
     590           0 :                         memcpy(&si, dataptr, 2);
     591           0 :                         dataptr += 2;
     592           0 :                         col_len = si;
     593           0 :                         break;
     594           0 :                 case 4:
     595           0 :                         memcpy(&li, dataptr, 4);
     596           0 :                         dataptr += 4;
     597           0 :                         col_len = li;
     598           0 :                         break;
     599        2320 :                 case 8:
     600        2320 :                         memcpy(&lli, dataptr, 8);
     601        2320 :                         dataptr += 8;
     602        2320 :                         col_len = lli;
     603             :                         if (lli != col_len)
     604             :                                 return TDS_FAIL;
     605             :                         break;
     606             :                 }
     607        2320 :                 if (col_len == SQL_NULL_DATA)
     608             :                         data_is_null = 1;
     609             :         }
     610             : 
     611             :         /* if (Max) column length specified take that into consideration. */
     612             : 
     613        4652 :         if (bindcol->column_bindlen == SQL_NULL_DATA)
     614             :                 data_is_null = 1;
     615        3530 :         else if (!data_is_null && bindcol->column_bindlen != SQL_VARLEN_DATA) {
     616        1770 :                 if (col_len != SQL_NULL_DATA)
     617         880 :                         col_len = ((TDS_INT8)bindcol->column_bindlen < col_len) ? bindcol->column_bindlen : col_len;
     618             :                 else
     619         890 :                         col_len = bindcol->column_bindlen;
     620             :         }
     621             : 
     622        4652 :         desttype = tds_get_conversion_type(bindcol->column_type, bindcol->column_size);
     623             : 
     624             :         /* Fixed Length data - this overrides anything else specified */
     625        4652 :         coltype = bindcol->column_bindtype == 0 ? desttype : (TDS_SERVER_TYPE) bindcol->column_bindtype;
     626        4652 :         if (is_fixed_type(coltype)) {
     627        1124 :                 col_len = tds_get_size_by_type(coltype);
     628             :         }
     629             : 
     630             :         /* read the data, finally */
     631             : 
     632        4652 :         if (!data_is_null && bindcol->bcp_term_len > 0) { /* terminated field */
     633           0 :                 bytes_read = _bcp_get_term_var(dataptr, bindcol->bcp_terminator, bindcol->bcp_term_len);
     634             : 
     635           0 :                 if (col_len != SQL_NULL_DATA)
     636           0 :                         col_len = (bytes_read < col_len) ? bytes_read : col_len;
     637             :                 else
     638             :                         col_len = bytes_read;
     639             :         }
     640             : 
     641        4652 :         if (data_is_null) {
     642        2242 :                 bindcol->bcp_column_data->datalen = 0;
     643        2242 :                 bindcol->bcp_column_data->is_null = true;
     644             :         } else {
     645        2410 :                 if ((converted_data_size =
     646        2410 :                      _tdsodbc_dbconvert(dbc, coltype,
     647             :                                dataptr, col_len,
     648        2410 :                                desttype, bindcol->bcp_column_data->data, bindcol)) == -1) {
     649             :                         return TDS_FAIL;
     650             :                 }
     651             : 
     652        2410 :                 bindcol->bcp_column_data->datalen = converted_data_size;
     653        2410 :                 bindcol->bcp_column_data->is_null = false;
     654             :         }
     655             : 
     656             :         return TDS_SUCCESS;
     657             : }
     658             : 
     659             : /**
     660             :  * Get the data for bcp-in from program variables, where the program data
     661             :  * have been identified as character terminated,
     662             :  * This is a low-level, internal function.  Call it correctly.
     663             :  */
     664             : static SQLLEN
     665           0 : _bcp_get_term_var(const TDS_CHAR * pdata, const TDS_CHAR * term, int term_len)
     666             : {
     667             :         SQLLEN bufpos;
     668             : 
     669           0 :         assert(term_len > 0);
     670             : 
     671           0 :         if (term_len == 1 && *term == '\0')  /* significant optimization for very common case */
     672           0 :                 return strlen(pdata);
     673             : 
     674             :         /* if bufpos becomes negative, we probably failed to find the terminator */
     675           0 :         for (bufpos = 0; bufpos >= 0 && memcmp(pdata, term, term_len) != 0; pdata++) {
     676           0 :                 bufpos++;
     677             :         }
     678             : 
     679             :         assert(bufpos >= 0);
     680             :         return bufpos;
     681             : }
     682             : 
     683             : void
     684         952 : odbc_bcp_free_storage(TDS_DBC *dbc)
     685             : {
     686         952 :         tdsdump_log(TDS_DBG_FUNC, "_bcp_free_storage(%p)\n", dbc);
     687         952 :         assert(dbc);
     688             : 
     689         952 :         tds_free_bcpinfo(dbc->bcpinfo);
     690         952 :         dbc->bcpinfo = NULL;
     691         952 : }
     692             : 

Generated by: LCOV version 1.13