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

Generated by: LCOV version 1.13