LCOV - code coverage report
Current view: top level - src/ctlib - blk.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 337 459 73.4 %
Date: 2026-11-07 23:58:45 Functions: 14 24 58.3 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 1998-2004, 2005, 2010  Brian Bruns, Bill Thompson
       3             :  *
       4             :  * This library is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU Library General Public
       6             :  * License as published by the Free Software Foundation; either
       7             :  * version 2 of the License, or (at your option) any later version.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * Library General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU Library General Public
      15             :  * License along with this library; if not, write to the
      16             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      17             :  * Boston, MA 02111-1307, USA.
      18             :  */
      19             : 
      20             : #include <config.h>
      21             : 
      22             : #include <stdarg.h>
      23             : #include <stdio.h>
      24             : 
      25             : #if HAVE_STDLIB_H
      26             : #include <stdlib.h>
      27             : #endif /* HAVE_STDLIB_H */
      28             : 
      29             : #if HAVE_STRING_H
      30             : #include <string.h>
      31             : #endif /* HAVE_STRING_H */
      32             : 
      33             : #include <freetds/utils.h>
      34             : #include <freetds/replacements.h>
      35             : 
      36             : #include "bkpublic.h"
      37             : 
      38             : #include "ctpublic.h"
      39             : #include "ctlib.h"
      40             : 
      41             : static void _blk_null_error(TDSBCPINFO *bcpinfo, int index, int offset);
      42             : static TDSRET _blk_get_col_data(TDSBCPINFO * bulk, TDSCOLUMN * bcpcol, int index, int offset);
      43             : static CS_RETCODE _blk_rowxfer_in(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred);
      44             : static CS_RETCODE _blk_rowxfer_out(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred);
      45             : static void _blk_clean_desc(CS_BLKDESC * blkdesc);
      46             : 
      47             : #define CONN(bulk) ((CS_CONNECTION *) (bulk)->bcpinfo.parent)
      48             : 
      49             : TDS_COMPILE_CHECK(same_size, sizeof(CS_BLKDESC) == sizeof(TDSBCPINFO));
      50             : TDS_COMPILE_CHECK(nested_type, TDS_OFFSET(CS_BLKDESC, bcpinfo) == 0);
      51             : 
      52             : CS_RETCODE
      53         276 : blk_alloc(CS_CONNECTION * connection, CS_INT version, CS_BLKDESC ** blk_pointer)
      54             : {
      55             :         CS_BLKDESC *blkdesc;
      56             : 
      57         276 :         tdsdump_log(TDS_DBG_FUNC, "blk_alloc(%p, %d, %p)\n", connection, version, blk_pointer);
      58             : 
      59         276 :         if (!connection || !connection->tds_socket)
      60             :                 return CS_FAIL;
      61             : 
      62         276 :         if (connection->tds_socket->conn->tds_version < 0x500)
      63             :                 return CS_FAIL;
      64             : 
      65         276 :         blkdesc = (CS_BLKDESC *) tds_alloc_bcpinfo();
      66         276 :         if (!blkdesc)
      67             :                 return CS_FAIL;
      68             : 
      69             :         /* so we know who we belong to */
      70         276 :         blkdesc->bcpinfo.parent = connection;
      71             : 
      72         276 :         *blk_pointer = blkdesc;
      73         276 :         return CS_SUCCEED;
      74             : }
      75             : 
      76             : 
      77             : CS_RETCODE
      78        1768 : blk_bind(CS_BLKDESC * blkdesc, CS_INT item, CS_DATAFMT * datafmt_arg, CS_VOID * buffer, CS_INT * datalen, CS_SMALLINT * indicator)
      79             : {
      80             :         TDSCOLUMN *colinfo;
      81             :         CS_CONNECTION *con;
      82             :         CS_INT bind_count;
      83             :         const CS_DATAFMT_COMMON * datafmt;
      84             :         int i;
      85             : 
      86        1768 :         tdsdump_log(TDS_DBG_FUNC, "blk_bind(%p, %d, %p, %p, %p, %p)\n", blkdesc, item, datafmt_arg, buffer, datalen, indicator);
      87             : 
      88        1768 :         if (!blkdesc)
      89             :                 return CS_FAIL;
      90             : 
      91        1768 :         con = CONN(blkdesc);
      92             : 
      93        1768 :         datafmt = _ct_datafmt_common(con->ctx, datafmt_arg);
      94             : 
      95        1768 :         if (item == CS_UNUSED) {
      96             :                 /* clear all bindings */
      97           0 :                 if (datafmt == NULL && buffer == NULL && datalen == NULL && indicator == NULL ) { 
      98           0 :                         blkdesc->bcpinfo.bind_count = CS_UNUSED;
      99           0 :                         for (i = 0; i < blkdesc->bcpinfo.bindinfo->num_cols; i++ ) {
     100           0 :                                 colinfo = blkdesc->bcpinfo.bindinfo->columns[i];
     101           0 :                                 colinfo->column_varaddr  = NULL;
     102           0 :                                 colinfo->column_bindtype = 0;
     103           0 :                                 colinfo->column_bindfmt  = 0;
     104           0 :                                 colinfo->column_bindlen  = 0;
     105           0 :                                 colinfo->column_nullbind = NULL;
     106           0 :                                 colinfo->column_lenbind  = NULL;
     107             :                         }
     108             :                 }
     109             :                 return CS_SUCCEED;
     110             :         }
     111             : 
     112             :         /* check item value */
     113             : 
     114        1768 :         if (item < 1 || item > blkdesc->bcpinfo.bindinfo->num_cols) {
     115           0 :                 _ctclient_msg(NULL, con, "blk_bind", 2, 5, 1, 141, "%s, %d", "colnum", item);
     116           0 :                 return CS_FAIL;
     117             :         }
     118             : 
     119             :         /* clear bindings for this column */
     120             : 
     121        1768 :         if (datafmt == NULL && buffer == NULL && datalen == NULL && indicator == NULL ) { 
     122             : 
     123           0 :                 colinfo = blkdesc->bcpinfo.bindinfo->columns[item - 1];
     124           0 :                 colinfo->column_varaddr  = NULL;
     125           0 :                 colinfo->column_bindtype = 0;
     126           0 :                 colinfo->column_bindfmt  = 0;
     127           0 :                 colinfo->column_bindlen  = 0;
     128           0 :                 colinfo->column_nullbind = NULL;
     129           0 :                 colinfo->column_lenbind  = NULL;
     130             : 
     131           0 :                 return CS_SUCCEED;
     132             :         }
     133             : 
     134        1768 :         if (datafmt == NULL)
     135             :                 return CS_FAIL;
     136             : 
     137             :         /*
     138             :          * check whether the request is for array binding and ensure that user
     139             :          * supplies the same datafmt->count to the subsequent ct_bind calls
     140             :          */
     141             : 
     142        1768 :         bind_count = (datafmt->count == 0) ? 1 : datafmt->count;
     143             : 
     144             :         /* first bind for this result set */
     145             : 
     146        1768 :         if (blkdesc->bcpinfo.bind_count == CS_UNUSED) {
     147         426 :                 blkdesc->bcpinfo.bind_count = bind_count;
     148             :         } else {
     149             :                 /* all subsequent binds for this result set - the bind counts must be the same */
     150        1342 :                 if (blkdesc->bcpinfo.bind_count != bind_count) {
     151           0 :                         _ctclient_msg(NULL, con, "blk_bind", 1, 1, 1, 137, "%d, %d", bind_count, blkdesc->bcpinfo.bind_count);
     152           0 :                         return CS_FAIL;
     153             :                 }
     154             :         }
     155             : 
     156             :         /* bind the column_varaddr to the address of the buffer */
     157             : 
     158        1768 :         colinfo = blkdesc->bcpinfo.bindinfo->columns[item - 1];
     159             : 
     160        1768 :         colinfo->column_varaddr = (char *) buffer;
     161        1768 :         colinfo->column_bindtype = datafmt->datatype;
     162        1768 :         colinfo->column_bindfmt = datafmt->format;
     163        1768 :         colinfo->column_bindlen = datafmt->maxlength;
     164        1768 :         if (indicator) {
     165        1320 :                 colinfo->column_nullbind = indicator;
     166             :         }
     167        1768 :         if (datalen) {
     168        1768 :                 colinfo->column_lenbind = datalen;
     169             :         }
     170             :         return CS_SUCCEED;
     171             : }
     172             : 
     173             : CS_RETCODE
     174           0 : blk_colval(SRV_PROC * srvproc, CS_BLKDESC * blkdescp, CS_BLK_ROW * rowp, CS_INT colnum, CS_VOID * valuep, CS_INT valuelen,
     175             :            CS_INT * outlenp)
     176             : {
     177             : 
     178           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_colval(%p, %p, %p, %d, %p, %d, %p)\n", 
     179             :                                 srvproc, blkdescp, rowp, colnum, valuep, valuelen, outlenp);
     180             : 
     181           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_colval()\n");
     182           0 :         return CS_FAIL;
     183             : }
     184             : 
     185             : CS_RETCODE
     186           0 : blk_default(CS_BLKDESC * blkdesc, CS_INT colnum, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
     187             : {
     188             : 
     189           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_default(%p, %d, %p, %d, %p)\n", blkdesc, colnum, buffer, buflen, outlen);
     190             : 
     191           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_default()\n");
     192           0 :         return CS_FAIL;
     193             : }
     194             : 
     195             : CS_RETCODE
     196        1192 : blk_describe(CS_BLKDESC * blkdesc, CS_INT item, CS_DATAFMT * datafmt_arg)
     197             : {
     198             :         TDSCOLUMN *curcol;
     199             :         CS_INT status, datatype;
     200             :         CS_DATAFMT_LARGE *datafmt;
     201             :         CS_DATAFMT_LARGE datafmt_buf;
     202             : 
     203        1192 :         tdsdump_log(TDS_DBG_FUNC, "blk_describe(%p, %d, %p)\n", blkdesc, item, datafmt_arg);
     204             : 
     205        1192 :         if (!blkdesc)
     206             :                 return CS_FAIL;
     207             : 
     208        1192 :         datafmt = _ct_datafmt_conv_prepare(CONN(blkdesc)->ctx, datafmt_arg, &datafmt_buf);
     209             : 
     210        1192 :         if (item < 1 || item > blkdesc->bcpinfo.bindinfo->num_cols) {
     211           0 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_describe", 2, 5, 1, 141, "%s, %d", "colnum", item);
     212           0 :                 return CS_FAIL;
     213             :         }
     214             : 
     215        1192 :         curcol = blkdesc->bcpinfo.bindinfo->columns[item - 1];
     216             :         /* name is always null terminated */
     217        2384 :         strlcpy(datafmt->name, tds_dstr_cstr(&curcol->column_name), sizeof(datafmt->name));
     218        1192 :         datafmt->namelen = (CS_INT) strlen(datafmt->name);
     219             :         /* need to turn the SYBxxx into a CS_xxx_TYPE */
     220        1192 :         datatype = _ct_get_client_type(curcol, true);
     221        1192 :         if (datatype == CS_ILLEGAL_TYPE)
     222             :                 return CS_FAIL;
     223        1192 :         datafmt->datatype = datatype;
     224        1192 :         tdsdump_log(TDS_DBG_INFO1, "blk_describe() datafmt->datatype = %d server type %d\n", datatype,
     225             :                         curcol->column_type);
     226             :         /* FIXME is ok this value for numeric/decimal? */
     227        1192 :         datafmt->maxlength = curcol->column_size;
     228        1192 :         datafmt->usertype = curcol->column_usertype;
     229        1192 :         datafmt->precision = curcol->column_prec;
     230        1192 :         datafmt->scale = curcol->column_scale;
     231             : 
     232             :         /*
     233             :          * There are other options that can be returned, but these are the
     234             :          * only two being noted via the TDS layer.
     235             :          */
     236        1192 :         status = 0;
     237        1192 :         if (curcol->column_nullable)
     238         656 :                 status |= CS_CANBENULL;
     239        1192 :         if (curcol->column_identity)
     240           0 :                 status |= CS_IDENTITY;
     241        1192 :         datafmt->status = status;
     242             : 
     243        1192 :         datafmt->count = 1;
     244        1192 :         datafmt->locale = NULL;
     245             : 
     246        1192 :         _ct_datafmt_conv_back(datafmt_arg, datafmt);
     247        1192 :         return CS_SUCCEED;
     248             : }
     249             : 
     250             : CS_RETCODE
     251         508 : blk_done(CS_BLKDESC * blkdesc, CS_INT type, CS_INT * outrow)
     252             : {
     253             :         TDSSOCKET *tds;
     254             :         int rows_copied;
     255             : 
     256         508 :         tdsdump_log(TDS_DBG_FUNC, "blk_done(%p, %d, %p)\n", blkdesc, type, outrow);
     257             : 
     258         508 :         tds = CONN(blkdesc)->tds_socket;
     259             : 
     260             :         /* text/image data still to be sent with blk_textxfer */
     261         508 :         if ((type == CS_BLK_BATCH || type == CS_BLK_ALL) && blkdesc->bcpinfo.blob_pending) {
     262          16 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 1, 1, 1, 1, "%s, %s", "blk_done()", "text data pending");
     263          16 :                 return CS_FAIL;
     264             :         }
     265             : 
     266         492 :         if (blkdesc->bcpinfo.direction == CS_BLK_OUT && type == CS_BLK_BATCH) {
     267          10 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 1, 1, 1, 16, "");
     268          10 :                 return CS_FAIL;
     269             :         }
     270             : 
     271             :         /* nothing transferred, nothing to complete */
     272         482 :         if ((type == CS_BLK_BATCH || type == CS_BLK_ALL) && !blkdesc->bcpinfo.xfer_init) {
     273          10 :                 if (outrow)
     274          10 :                         *outrow = 0;
     275          10 :                 if (type == CS_BLK_ALL)
     276             :                         _blk_clean_desc(blkdesc);
     277             :                 return CS_SUCCEED;
     278             :         }
     279             : 
     280         472 :         if (blkdesc->bcpinfo.direction == CS_BLK_OUT && type == CS_BLK_ALL) {
     281             :                 TDSRET rc;
     282             :                 TDS_INT result_type;
     283             : 
     284             :                 /* rows still to retrieve, client can continue or cancel */
     285          20 :                 if (!blkdesc->bcpinfo.out_done) {
     286          10 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 1, 1, 1, 163, "");
     287          10 :                         return CS_FAIL;
     288             :                 }
     289             : 
     290             :                 /* discard the rest of the results */
     291          20 :                 while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS)
     292          10 :                         continue;
     293          10 :                 if (rc != TDS_NO_MORE_RESULTS) {
     294           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
     295           0 :                         return CS_FAIL;
     296             :                 }
     297             : 
     298          10 :                 if (outrow)
     299          10 :                         *outrow = blkdesc->bcpinfo.rows_sent;
     300          10 :                 _blk_clean_desc(blkdesc);
     301          10 :                 return CS_SUCCEED;
     302             :         }
     303             : 
     304         452 :         switch (type) {
     305          36 :         case CS_BLK_BATCH:
     306          36 :                 if (TDS_FAILED(tds_bcp_done(tds, &rows_copied))) {
     307           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
     308           0 :                         return CS_FAIL;
     309             :                 }
     310             :                 
     311          36 :                 if (outrow) 
     312          36 :                         *outrow = rows_copied;
     313             :                 
     314          36 :                 if (TDS_FAILED(tds_bcp_start(tds, &blkdesc->bcpinfo))) {
     315           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
     316           0 :                         return CS_FAIL;
     317             :                 }
     318             :                 break;
     319             :                 
     320         320 :         case CS_BLK_ALL:
     321         320 :                 if (TDS_FAILED(tds_bcp_done(tds, &rows_copied))) {
     322           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
     323           0 :                         return CS_FAIL;
     324             :                 }
     325             :                 
     326         320 :                 if (outrow) 
     327         320 :                         *outrow = rows_copied;
     328             : 
     329             :                 /* free allocated storage in blkdesc & initialise flags, etc. */
     330             :                 _blk_clean_desc(blkdesc);
     331             :                 break;
     332             : 
     333          96 :         case CS_BLK_CANCEL:
     334          96 :                 if (blkdesc->bcpinfo.xfer_init) {
     335             :                         TDSRET rc;
     336             : 
     337          76 :                         if (blkdesc->bcpinfo.direction == CS_BLK_IN) {
     338          66 :                                 rc = tds_bcp_cancel(tds);
     339             :                         } else {
     340          10 :                                 rc = tds_send_cancel(tds);
     341          10 :                                 if (TDS_SUCCEED(rc))
     342          10 :                                         rc = tds_process_cancel(tds);
     343             :                         }
     344          76 :                         if (TDS_FAILED(rc)) {
     345           0 :                                 _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
     346           0 :                                 return CS_FAIL;
     347             :                         }
     348             :                 }
     349             : 
     350          96 :                 if (outrow)
     351          80 :                         *outrow = 0;
     352             : 
     353             :                 /* free allocated storage in blkdesc & initialise flags, etc. */
     354             :                 _blk_clean_desc(blkdesc);
     355             :                 break;
     356             : 
     357           0 :         default:
     358           0 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 1, 1, 1, 5, "%d, type", type);
     359           0 :                 return CS_FAIL;
     360             :         }
     361             : 
     362             :         return CS_SUCCEED;
     363             : }
     364             : 
     365             : /**
     366             :  * Free allocated storage in blkdesc and reset flags to allow a new blk_init.
     367             :  */
     368             : static void
     369             : _blk_clean_desc(CS_BLKDESC *blkdesc)
     370             : {
     371         436 :         tds_deinit_bcpinfo(&blkdesc->bcpinfo);
     372             : 
     373         436 :         blkdesc->bcpinfo.direction = 0;
     374         436 :         blkdesc->bcpinfo.bind_count = CS_UNUSED;
     375         436 :         blkdesc->bcpinfo.xfer_init = false;
     376         436 :         blkdesc->bcpinfo.out_done = false;
     377             : }
     378             : 
     379             : CS_RETCODE
     380         276 : blk_drop(CS_BLKDESC *blkdesc)
     381             : {
     382         276 :         tdsdump_log(TDS_DBG_FUNC, "blk_drop(%p)\n", blkdesc);
     383             : 
     384             :         /* this is possible as CS_BLKDESC contains just bcpinfo field */
     385         276 :         tds_free_bcpinfo(&blkdesc->bcpinfo);
     386             : 
     387         276 :         return CS_SUCCEED;
     388             : }
     389             : 
     390             : CS_RETCODE
     391           0 : blk_getrow(SRV_PROC * srvproc, CS_BLKDESC * blkdescp, CS_BLK_ROW * rowp)
     392             : {
     393           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_getrow(%p, %p, %p)\n", srvproc, blkdescp, rowp);
     394             : 
     395           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_getrow()\n");
     396           0 :         return CS_FAIL;
     397             : }
     398             : 
     399             : CS_RETCODE
     400           0 : blk_gettext(SRV_PROC * srvproc, CS_BLKDESC * blkdescp, CS_BLK_ROW * rowp, CS_INT bufsize, CS_INT * outlenp)
     401             : {
     402             : 
     403           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_gettext(%p, %p, %p, %d, %p)\n", srvproc, blkdescp, rowp, bufsize, outlenp);
     404             : 
     405           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_gettext()\n");
     406           0 :         return CS_FAIL;
     407             : }
     408             : 
     409             : CS_RETCODE
     410         456 : blk_init(CS_BLKDESC * blkdesc, CS_INT direction, CS_CHAR * tablename, CS_INT tnamelen)
     411             : {
     412         456 :         tdsdump_log(TDS_DBG_FUNC, "blk_init(%p, %d, %p, %d)\n", blkdesc, direction, tablename, tnamelen);
     413             : 
     414         456 :         if (!blkdesc) {
     415             :                 return CS_FAIL;
     416             :         }
     417             : 
     418         456 :         if (direction != CS_BLK_IN && direction != CS_BLK_OUT ) {
     419          10 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 15, "");
     420          10 :                 return CS_FAIL;
     421             :         }
     422             : 
     423         446 :         if (!tablename) {
     424          10 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 6, "tblname");
     425          10 :                 return CS_FAIL;
     426             :         }
     427         436 :         tnamelen = _ct_get_string_length(tablename, tnamelen);
     428         436 :         if (tnamelen < 0) {
     429          10 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 4, "tblnamelen, %d", tnamelen);
     430          10 :                 return CS_FAIL;
     431             :         }
     432             : 
     433             :         /* free allocated storage in blkdesc & initialise flags, etc. */
     434         426 :         tds_deinit_bcpinfo(&blkdesc->bcpinfo);
     435             : 
     436             :         /* string can be no-nul terminated so copy with memcpy */
     437         426 :         if (!tds_dstr_copyn(&blkdesc->bcpinfo.tablename, tablename, tnamelen)) {
     438             :                 return CS_FAIL;
     439             :         }
     440             : 
     441         426 :         blkdesc->bcpinfo.direction = direction;
     442         426 :         blkdesc->bcpinfo.bind_count = CS_UNUSED;
     443         426 :         blkdesc->bcpinfo.xfer_init = false;
     444         426 :         blkdesc->bcpinfo.rows_sent = 0;
     445         426 :         blkdesc->bcpinfo.out_done = false;
     446             : 
     447         426 :         if (TDS_FAILED(tds_bcp_init(CONN(blkdesc)->tds_socket, &blkdesc->bcpinfo))) {
     448           0 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 2, 5, 1, 140, "");
     449           0 :                 return CS_FAIL;
     450             :         }
     451         426 :         blkdesc->bcpinfo.bind_count = CS_UNUSED;
     452             : 
     453         426 :         return CS_SUCCEED;
     454             : }
     455             : 
     456             : CS_RETCODE
     457         100 : blk_props(CS_BLKDESC * blkdesc, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
     458             : {
     459             :         int retval, intval;
     460             : 
     461         100 :         tdsdump_log(TDS_DBG_FUNC, "blk_props(%p, %d, %d, %p, %d, %p)\n", blkdesc, action, property, buffer, buflen, outlen);
     462             : 
     463         100 :         switch (property) {
     464           0 :         case BLK_IDENTITY: 
     465           0 :                 switch (action) {
     466           0 :                 case CS_SET: 
     467           0 :                         if (buffer) {
     468           0 :                                 memcpy(&intval, buffer, sizeof(intval));
     469           0 :                                 if (intval == CS_TRUE)
     470           0 :                                         blkdesc->bcpinfo.identity_insert_on = true;
     471           0 :                                 if (intval == CS_FALSE)
     472           0 :                                         blkdesc->bcpinfo.identity_insert_on = false;
     473             :                         }
     474             :                         return CS_SUCCEED;
     475             :                         break;
     476           0 :                 case CS_GET:
     477           0 :                         retval = blkdesc->bcpinfo.identity_insert_on ? CS_TRUE : CS_FALSE ;
     478           0 :                         if (buffer) {
     479           0 :                                 memcpy (buffer, &retval, sizeof(retval));
     480           0 :                                 if (outlen)
     481           0 :                                         *outlen = sizeof(retval);
     482             :                         }
     483             :                         return CS_SUCCEED;
     484             :                         break;
     485           0 :                 default:
     486           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_props", 2, 5, 1, 141, "%s, %d", "action", action);
     487             :                         break;
     488             :                 }
     489           0 :                 break;
     490             : 
     491         100 :         case BLK_HINTS:
     492         100 :                 return _ct_props_dstr(CONN(blkdesc), &blkdesc->bcpinfo.hint, action, buffer, buflen, outlen);
     493             : 
     494           0 :         default:
     495           0 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_props", 2, 5, 1, 141, "%s, %d", "property", property);
     496           0 :                 break;
     497             :         }
     498             :         return CS_FAIL;
     499             : }
     500             : 
     501             : CS_RETCODE
     502           0 : blk_rowalloc(SRV_PROC * srvproc, CS_BLK_ROW ** row)
     503             : {
     504           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_rowalloc(%p, %p)\n", srvproc, row);
     505             : 
     506           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_rowalloc()\n");
     507           0 :         return CS_FAIL;
     508             : }
     509             : 
     510             : CS_RETCODE
     511           0 : blk_rowdrop(SRV_PROC * srvproc, CS_BLK_ROW * row)
     512             : {
     513           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_rowdrop(%p, %p)\n", srvproc, row);
     514             : 
     515           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_rowdrop()\n");
     516           0 :         return CS_FAIL;
     517             : }
     518             : 
     519             : CS_RETCODE
     520       61198 : blk_rowxfer(CS_BLKDESC * blkdesc)
     521             : {
     522       61198 :         tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer(%p)\n", blkdesc);
     523             : 
     524       61198 :         return blk_rowxfer_mult(blkdesc, NULL);
     525             : }
     526             : 
     527             : CS_RETCODE
     528       61358 : blk_rowxfer_mult(CS_BLKDESC * blkdesc, CS_INT * row_count)
     529             : {
     530       61358 :         CS_INT rows_to_xfer = 0;
     531       61358 :         CS_INT rows_xferred = 0;
     532             :         CS_RETCODE ret;
     533             : 
     534       61358 :         tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_mult(%p, %p)\n", blkdesc, row_count);
     535             : 
     536       61358 :         rows_to_xfer = blkdesc->bcpinfo.bind_count;
     537             : 
     538       61358 :         if (blkdesc->bcpinfo.direction == CS_BLK_IN) {
     539             :                 /* a positive row count limits rows to send, zero or negative values send all rows bound */
     540       61268 :                 if (row_count != NULL && *row_count > 0) {
     541          40 :                         if (*row_count > rows_to_xfer) {
     542          10 :                                 _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 1, 1, 1, 33, "");
     543          10 :                                 return CS_FAIL;
     544             :                         }
     545             :                         rows_to_xfer = *row_count;
     546             :                 }
     547             :                 /* text/image data still to be sent with blk_textxfer */
     548       61258 :                 if (blkdesc->bcpinfo.blob_pending) {
     549          16 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 1, 1, 1, 1, "%s, %s", "blk_rowxfer()",
     550             :                                       "text data pending");
     551          16 :                         return CS_FAIL;
     552             :                 }
     553       61242 :                 ret = _blk_rowxfer_in(blkdesc, rows_to_xfer, &rows_xferred);
     554             :         } else {
     555          90 :                 ret = _blk_rowxfer_out(blkdesc, rows_to_xfer, &rows_xferred);
     556             :         }
     557       61332 :         if (row_count)
     558         140 :                 *row_count = rows_xferred;
     559             :         return ret;
     560             : 
     561             : }
     562             : 
     563             : CS_RETCODE
     564           0 : blk_sendrow(CS_BLKDESC * blkdesc, CS_BLK_ROW * row)
     565             : {
     566             : 
     567           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_sendrow(%p, %p)\n", blkdesc, row);
     568             : 
     569           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_sendrow()\n");
     570           0 :         return CS_FAIL;
     571             : }
     572             : 
     573             : CS_RETCODE
     574           0 : blk_sendtext(CS_BLKDESC * blkdesc, CS_BLK_ROW * row, CS_BYTE * buffer, CS_INT buflen)
     575             : {
     576           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_sendtext(%p, %p, %p, %d)\n", blkdesc, row, buffer, buflen);
     577             : 
     578           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_sendtext()\n");
     579           0 :         return CS_FAIL;
     580             : }
     581             : 
     582             : CS_RETCODE
     583           0 : blk_srvinit(SRV_PROC * srvproc, CS_BLKDESC * blkdescp)
     584             : {
     585           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_srvinit(%p, %p)\n", srvproc, blkdescp);
     586             : 
     587           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_srvinit()\n");
     588           0 :         return CS_FAIL;
     589             : }
     590             : 
     591             : CS_RETCODE
     592         624 : blk_textxfer(CS_BLKDESC *blkdesc, CS_BYTE *buffer, CS_INT buflen, CS_INT *outlen)
     593             : {
     594             :         TDSBCPINFO *bcpinfo;
     595             :         bool end;
     596             : 
     597         624 :         tdsdump_log(TDS_DBG_FUNC, "blk_textxfer(%p, %p, %d, %p)\n", blkdesc, buffer, buflen, outlen);
     598             : 
     599         624 :         if (!blkdesc)
     600             :                 return CS_FAIL;
     601             : 
     602         624 :         bcpinfo = &blkdesc->bcpinfo;
     603         624 :         if (bcpinfo->direction != CS_BLK_IN) {
     604           0 :                 tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_textxfer() for copy out\n");
     605             :                 return CS_FAIL;
     606             :         }
     607             : 
     608         624 :         if (!bcpinfo->blob_pending) {
     609          32 :                 if (!bcpinfo->xfer_init)
     610          16 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_textxfer", 1, 1, 1, 1, "%s, %s", "blk_textxfer()", "no row sent");
     611             :                 else
     612          16 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_textxfer", 1, 1, 1, 49, "");
     613             :                 return CS_FAIL;
     614             :         }
     615             : 
     616         592 :         if (buflen < 0 || (buflen > 0 && !buffer)) {
     617           0 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_textxfer", 1, 1, 1, 5, "%d, %s", buflen, "buflen");
     618           0 :                 return CS_FAIL;
     619             :         }
     620             : 
     621         592 :         if (buflen > bcpinfo->blob_left) {
     622          16 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_textxfer", 1, 1, 1, 7, "%d", buflen);
     623          16 :                 return CS_FAIL;
     624             :         }
     625             : 
     626         576 :         end = (buflen == bcpinfo->blob_left);
     627         576 :         if (TDS_FAILED(tds_bcp_send_blob_data(CONN(blkdesc)->tds_socket, bcpinfo, buffer, buflen))) {
     628           0 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_textxfer", 2, 5, 1, 140, "");
     629           0 :                 return CS_FAIL;
     630             :         }
     631             : 
     632         576 :         return end ? CS_END_DATA : CS_SUCCEED;
     633             : }
     634             : 
     635             : static CS_RETCODE
     636          90 : _blk_rowxfer_out(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred)
     637             : {
     638             :         TDSSOCKET *tds;
     639             :         TDS_INT result_type;
     640             :         TDSRET ret;
     641             :         TDS_INT temp_count;
     642             : 
     643          90 :         tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_out(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
     644             : 
     645          90 :         if (!blkdesc || !CONN(blkdesc))
     646             :                 return CS_FAIL;
     647             : 
     648          90 :         tds = CONN(blkdesc)->tds_socket;
     649             : 
     650             :         /*
     651             :          * the first time blk_xfer called after blk_init()
     652             :          * do the query and get to the row data...
     653             :          */
     654             : 
     655          90 :         if (!blkdesc->bcpinfo.xfer_init) {
     656             : 
     657          40 :                 if (TDS_FAILED(tds_submit_queryf(tds, "select * from %s", tds_dstr_cstr(&blkdesc->bcpinfo.tablename)))) {
     658           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
     659           0 :                         return CS_FAIL;
     660             :                 }
     661             : 
     662          40 :                 while ((ret = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
     663          40 :                         if (result_type == TDS_ROW_RESULT)
     664             :                                 break;
     665             :                 }
     666             :         
     667          20 :                 if (ret != TDS_SUCCESS || result_type != TDS_ROW_RESULT) {
     668           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
     669           0 :                         return CS_FAIL;
     670             :                 }
     671             : 
     672          20 :                 blkdesc->bcpinfo.xfer_init = true;
     673             :         }
     674             : 
     675          90 :         if (rows_xferred)
     676          90 :                 *rows_xferred = 0;
     677             : 
     678          90 :         if (blkdesc->bcpinfo.out_done)
     679             :                 return CS_END_DATA;
     680             : 
     681         100 :         for (temp_count = 0; temp_count < rows_to_xfer; temp_count++) {
     682             : 
     683         110 :                 ret = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
     684             : 
     685         110 :                 tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_out() process_row_tokens returned %d\n", ret);
     686             : 
     687         110 :                 switch (ret) {
     688         110 :                 case TDS_SUCCESS:
     689         110 :                         if (result_type == TDS_ROW_RESULT || result_type == TDS_COMPUTE_RESULT) {
     690         100 :                                 if (result_type == TDS_ROW_RESULT) {
     691         100 :                                         blkdesc->bcpinfo.rows_sent++;
     692         100 :                                         if (_ct_bind_data( CONN(blkdesc)->ctx, tds->current_results, blkdesc->bcpinfo.bindinfo, temp_count))
     693             :                                                 return CS_ROW_FAIL;
     694         100 :                                         if (rows_xferred)
     695         100 :                                                 *rows_xferred = *rows_xferred + 1;
     696             :                                 }
     697             :                                 break;
     698             :                         }
     699             :                 case TDS_NO_MORE_RESULTS:
     700          10 :                         blkdesc->bcpinfo.out_done = true;
     701             :                         /* return rows retrieved, CS_END_DATA is returned by next call */
     702          10 :                         return (rows_xferred && *rows_xferred > 0) ? CS_SUCCEED : CS_END_DATA;
     703             : 
     704           0 :                 default:
     705           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
     706           0 :                         return CS_FAIL;
     707             :                         break;
     708             :                 }
     709             :         } 
     710             : 
     711             :         return CS_SUCCEED;
     712             : }
     713             : 
     714             : static CS_RETCODE
     715       61242 : _blk_rowxfer_in(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred)
     716             : {
     717             :         TDSSOCKET *tds;
     718             :         TDS_INT each_row;
     719             : 
     720       61242 :         tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_in(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
     721             : 
     722       61242 :         if (!blkdesc)
     723             :                 return CS_FAIL;
     724             : 
     725       61242 :         tds = CONN(blkdesc)->tds_socket;
     726             : 
     727             :         /*
     728             :          * the first time blk_xfer called after blk_init()
     729             :          * do the query and get to the row data...
     730             :          */
     731             : 
     732       61242 :         if (!blkdesc->bcpinfo.xfer_init) {
     733             : 
     734             :                 /*
     735             :                  * first call the start_copy function, which will
     736             :                  * retrieve details of the database table columns
     737             :                  */
     738             : 
     739         386 :                 if (TDS_FAILED(tds_bcp_start_copy_in(tds, &blkdesc->bcpinfo))) {
     740           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
     741           0 :                         return CS_FAIL;
     742             :                 }
     743             : 
     744         386 :                 blkdesc->bcpinfo.xfer_init = true;
     745             :         } 
     746             : 
     747       61130 :         for (each_row = 0; each_row < rows_to_xfer; each_row++) {
     748             : 
     749       61332 :                 if (tds_bcp_send_record(tds, &blkdesc->bcpinfo, _blk_get_col_data, _blk_null_error, each_row) != TDS_SUCCESS) {
     750             :                         /* FIXME */
     751             :                         return CS_FAIL;
     752             :                 }
     753       61242 :                 if (rows_xferred)
     754       61242 :                         *rows_xferred = each_row + 1;
     755             : 
     756             :                 /* data to be sent with blk_textxfer, stop here */
     757       61242 :                 if (blkdesc->bcpinfo.blob_pending)
     758             :                         break;
     759             :         }
     760             : 
     761             :         return CS_SUCCEED;
     762             : }
     763             : 
     764             : static void
     765           0 : _blk_null_error(TDSBCPINFO *bcpinfo, int index, int offset)
     766             : {
     767           0 :         CS_BLKDESC *blkdesc = (CS_BLKDESC *) bcpinfo;
     768             : 
     769           0 :         tdsdump_log(TDS_DBG_FUNC, "_blk_null_error(%p, %d, %d)\n", bcpinfo, index, offset);
     770             : 
     771           0 :         _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 7, 1, 142, "%d, %d",  index + 1, offset + 1);
     772           0 : }
     773             : 
     774             : /** How to handle data too long for a character or binary column */
     775             : typedef enum
     776             : {
     777             :         /** truncate data */
     778             :         BLK_TRUNC_SILENT,
     779             :         /** truncate data and report a warning */
     780             :         BLK_TRUNC_WARN,
     781             :         /** report an error, row is not sent */
     782             :         BLK_TRUNC_FAIL,
     783             : } blk_truncation_mode;
     784             : 
     785             : static bool
     786             : _blk_is_binary_source(CS_INT srctype)
     787             : {
     788          60 :         return srctype == CS_BINARY_TYPE || srctype == CS_LONGBINARY_TYPE || srctype == CS_IMAGE_TYPE;
     789             : }
     790             : 
     791             : /**
     792             :  * Tell how to handle data too long for a character or binary column.
     793             :  * Follows Sybase/SAP library, which depends on source type.
     794             :  */
     795             : static blk_truncation_mode
     796         170 : _blk_truncation_mode(CS_INT srctype, bool binary_dest)
     797             : {
     798         170 :         switch (srctype) {
     799          60 :         case CS_CHAR_TYPE:
     800             :         case CS_LONGCHAR_TYPE:
     801             :         case CS_TEXT_TYPE:
     802             :         case CS_UNICHAR_TYPE:
     803             :         case CS_UNITEXT_TYPE:
     804          60 :                 return binary_dest ? BLK_TRUNC_WARN : BLK_TRUNC_SILENT;
     805          20 :         case CS_VARCHAR_TYPE:
     806          20 :                 return binary_dest ? BLK_TRUNC_FAIL : BLK_TRUNC_WARN;
     807          20 :         case CS_BINARY_TYPE:
     808             :         case CS_IMAGE_TYPE:
     809          20 :                 return binary_dest ? BLK_TRUNC_SILENT : BLK_TRUNC_WARN;
     810             :         case CS_LONGBINARY_TYPE:
     811             :                 return BLK_TRUNC_WARN;
     812          20 :         case CS_VARBINARY_TYPE:
     813          20 :                 return BLK_TRUNC_FAIL;
     814          10 :         case CS_DATETIME_TYPE:
     815             :         case CS_DATETIME4_TYPE:
     816             :         case CS_DATE_TYPE:
     817             :         case CS_TIME_TYPE:
     818             :         case CS_BIGDATETIME_TYPE:
     819             :         case CS_BIGTIME_TYPE:
     820          10 :                 return binary_dest ? BLK_TRUNC_SILENT : BLK_TRUNC_WARN;
     821          20 :         default:
     822             :                 /* numeric types */
     823          20 :                 return binary_dest ? BLK_TRUNC_WARN : BLK_TRUNC_FAIL;
     824             :         }
     825             : }
     826             : 
     827             : static TDSRET
     828      125784 : _blk_get_col_data(TDSBCPINFO *bulk, TDSCOLUMN *bindcol, int index TDS_UNUSED, int offset)
     829             : {
     830      125784 :         bool null_column = false;
     831      125784 :         unsigned char *src = NULL;
     832             : 
     833      125784 :         CS_INT      srctype = 0;
     834      125784 :         CS_INT      srclen  = 0;
     835      125784 :         TDS_INT     destlen  = 0;
     836      125784 :         CS_SMALLINT *nullind = NULL;
     837      125784 :         CS_INT      *datalen = NULL;
     838      125784 :         CS_BLKDESC *blkdesc = (CS_BLKDESC *) bulk;
     839      125784 :         CS_CONTEXT *ctx = CONN(blkdesc)->ctx;
     840             : 
     841      125784 :         tdsdump_log(TDS_DBG_FUNC, "_blk_get_col_data(%p, %p, %d)\n", bulk, bindcol, offset);
     842             : 
     843             :         /*
     844             :          * Retrieve the initial bound column_varaddress
     845             :          * and increment it if offset specified
     846             :          */
     847             : 
     848      125784 :         if (bindcol->column_nullbind) {
     849        4646 :                 nullind = bindcol->column_nullbind;
     850        4646 :                 nullind += offset;
     851             :         }
     852      125784 :         if (bindcol->column_lenbind) {
     853      125784 :                 datalen = bindcol->column_lenbind;
     854      125784 :                 datalen += offset;
     855             :         }
     856             : 
     857      125784 :         src = (unsigned char *) bindcol->column_varaddr;
     858      125784 :         if (!src) {
     859             :                 /*
     860             :                  * Text/image columns bound with a NULL buffer, data will be
     861             :                  * sent using blk_textxfer, bound length is the total length.
     862             :                  */
     863         272 :                 if (is_blob_col(bindcol) && datalen && *datalen >= 0) {
     864         272 :                         bindcol->bcp_column_data->is_null = (nullind && *nullind == -1);
     865         272 :                         bindcol->bcp_column_data->datalen = bindcol->bcp_column_data->is_null ? 0 : *datalen;
     866             :                         /* empty data, nothing to send later */
     867         272 :                         bindcol->bcp_column_data->deferred = (bindcol->bcp_column_data->datalen > 0);
     868         272 :                         return TDS_SUCCESS;
     869             :                 }
     870           0 :                 tdsdump_log(TDS_DBG_ERROR, "error source field not addressable\n");
     871             :                 return TDS_FAIL;
     872             :         }
     873             : 
     874      125512 :         src += offset * bindcol->column_bindlen;
     875             : 
     876      125512 :         srctype = bindcol->column_bindtype;  /* passes to cs_convert */
     877             : 
     878      125512 :         tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data srctype = %d\n", srctype);
     879      125512 :         tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data datalen = %d\n", datalen ? *datalen : -1);
     880             : 
     881      125512 :         if (datalen) {
     882      125512 :                 srclen = *datalen;
     883      125512 :                 if (srclen == CS_UNUSED) {
     884             :                         /* length of fixed types is implicit */
     885         204 :                         if (srctype == CS_NUMERIC_TYPE || srctype == CS_DECIMAL_TYPE) {
     886             :                                 srclen = sizeof(CS_NUMERIC);
     887             :                         } else {
     888         184 :                                 TDS_SERVER_TYPE type = _ct_get_server_type(NULL, srctype);
     889             : 
     890         184 :                                 srclen = type == TDS_INVALID_TYPE ? -1 : tds_get_size_by_type(type);
     891         184 :                                 if (srclen <= 0) {
     892           0 :                                         tdsdump_log(TDS_DBG_ERROR, "Not fixed length type (%d) and datalen not specified\n",
     893             :                                                     bindcol->column_bindtype);
     894             :                                         return TDS_FAIL;
     895             :                                 }
     896             :                         }
     897             :                 }
     898      125492 :                 if (srclen < 0) {
     899           0 :                         tdsdump_log(TDS_DBG_ERROR, "Invalid datalen specified (%d)\n", srclen);
     900             :                         return TDS_FAIL;
     901             :                 }
     902             :         }
     903      125512 :         if (srclen == 0) {
     904        1560 :                 if (nullind && *nullind == -1)
     905             :                         null_column = true;
     906             :         }
     907             : 
     908             :         if (!null_column) {
     909             :                 CS_DATAFMT_COMMON srcfmt;
     910             :                 TDS_SERVER_TYPE desttype;
     911      123952 :                 CONV_RESULT cres, *p_cres = &cres;
     912      123952 :                 bool replace = false;
     913             : 
     914      123952 :                 srcfmt.datatype = srctype;
     915      123952 :                 srcfmt.maxlength = srclen;
     916             : 
     917      123952 :                 desttype = tds_get_conversion_type(bindcol->on_server.column_type, bindcol->on_server.column_size);
     918             :                 /*
     919             :                  * For Unicode columns convert to client character type
     920             :                  * and later convert to server encoding
     921             :                  */
     922      123952 :                 if (is_unicode_type(bindcol->on_server.column_type))
     923          16 :                         desttype = tds_get_conversion_type(bindcol->column_type, bindcol->column_size);
     924             : 
     925      123952 :                 switch (desttype) {
     926             :                         /* binary types not BLOB (with limited size) */
     927         470 :                 case SYBBINARY:
     928             :                 case SYBVARBINARY:
     929             :                 case XSYBBINARY:
     930             :                 case XSYBVARBINARY:
     931             :                         /* conversion from char to binary are a bit peculiar */
     932         470 :                         switch (srctype) {
     933          10 :                         case CS_VARCHAR_TYPE:
     934             :                                 {
     935          10 :                                         CS_VARCHAR *vc = (CS_VARCHAR *) src;
     936             : 
     937          10 :                                         srcfmt.maxlength = TDS_CLAMP(vc->len, 0, sizeof(vc->str));
     938             :                                 }
     939         200 :                         case CS_CHAR_TYPE:
     940             :                         case CS_LONGCHAR_TYPE:
     941             :                         case CS_TEXT_TYPE:
     942         200 :                                 desttype = TDS_CONVERT_BINARY;
     943         200 :                                 cres.cb.len = (srcfmt.maxlength + 1) / 2;
     944         200 :                                 cres.cb.len = TDS_MIN(cres.cb.len, bindcol->on_server.column_size);
     945         200 :                                 cres.cb.ib = malloc(cres.cb.len);
     946         200 :                                 if (!cres.cb.ib)
     947          90 :                                         return TDS_FAIL;
     948         200 :                                 free(bindcol->bcp_column_data->data);
     949         200 :                                 bindcol->bcp_column_data->data = (void *) cres.cb.ib;
     950         200 :                                 break;
     951             :                         default:
     952             :                                 replace = true;
     953             :                                 break;
     954             :                         }
     955             :                         break;
     956             :                 case SYBIMAGE:
     957             :                 case SYBLONGBINARY:
     958             :                 case SYBCHAR:
     959             :                 case SYBVARCHAR:
     960             :                 case SYBTEXT:
     961             :                 case XSYBCHAR:
     962             :                 case XSYBVARCHAR:
     963             :                         replace = true;
     964             :                         break;
     965         260 :                 case SYBNUMERIC:
     966             :                 case SYBDECIMAL:
     967         260 :                         p_cres = (CONV_RESULT *) bindcol->bcp_column_data->data;
     968         260 :                         p_cres->n.precision = bindcol->column_prec;
     969         260 :                         p_cres->n.scale = bindcol->column_scale;
     970         260 :                         break;
     971       62266 :                 default:
     972       62266 :                         p_cres = (CONV_RESULT *) bindcol->bcp_column_data->data;
     973       62266 :                         break;
     974             :                 }
     975             : 
     976             :                 /* if convert return FAIL mark error but process other columns */
     977      123952 :                 destlen = _cs_cs2tds(ctx, &srcfmt, src, desttype, p_cres);
     978      123952 :                 if (destlen < 0) {
     979          50 :                         switch (destlen) {
     980          40 :                         case TDS_CONVERT_SYNTAX:
     981          40 :                                 _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 1, 2, 1, 26, "%d, %d", index + 1,
     982          40 :                                               bulk->rows_sent + 1);
     983          40 :                                 break;
     984          10 :                         case TDS_CONVERT_OVERFLOW:
     985          10 :                                 _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 1, 2, 1, 25, "%d, %d", index + 1,
     986          10 :                                               bulk->rows_sent + 1);
     987          10 :                                 break;
     988             :                         }
     989             : 
     990          50 :                         tdsdump_log(TDS_DBG_ERROR, "conversion from srctype %d to TDS type %d failed\n", srctype, desttype);
     991             :                         return TDS_FAIL;
     992             :                 }
     993             : 
     994      123902 :                 if (replace) {
     995       61226 :                         free(bindcol->bcp_column_data->data);
     996       61226 :                         bindcol->bcp_column_data->data = (void *) cres.c;
     997             :                 }
     998             : 
     999             :                 /* convert character data to server encoding */
    1000      123902 :                 if (is_unicode_type(bindcol->on_server.column_type) && is_char_type(desttype) && bindcol->char_conv && destlen > 0) {
    1001             :                         size_t out_len;
    1002             :                         const char *converted;
    1003             : 
    1004          32 :                         converted = tds_convert_string(CONN(blkdesc)->tds_socket, bindcol->char_conv,
    1005          16 :                                                        (const char *) bindcol->bcp_column_data->data, destlen, &out_len);
    1006          16 :                         if (!converted) {
    1007           0 :                                 _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 1, 2, 1, 26, "%d, %d", index + 1,
    1008           0 :                                               bulk->rows_sent + 1);
    1009           0 :                                 return TDS_FAIL;
    1010             :                         }
    1011          16 :                         if (converted != (const char *) bindcol->bcp_column_data->data) {
    1012          16 :                                 free(bindcol->bcp_column_data->data);
    1013          16 :                                 bindcol->bcp_column_data->data = (TDS_UCHAR *) converted;
    1014             :                         }
    1015          16 :                         destlen = (TDS_INT) out_len;
    1016             :                 }
    1017             : 
    1018             :                 /* data too long for character or binary column */
    1019      123902 :                 if (!is_blob_col(bindcol) && destlen > bindcol->on_server.column_size
    1020         430 :                     && (desttype == TDS_CONVERT_BINARY || is_binary_type(desttype) || is_char_type(desttype))) {
    1021         170 :                         bool binary_dest = (desttype == TDS_CONVERT_BINARY || is_binary_type(desttype));
    1022             : 
    1023         170 :                         switch (_blk_truncation_mode(srctype, binary_dest)) {
    1024          40 :                         case BLK_TRUNC_FAIL:
    1025          40 :                                 _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 1, 2, 1, 25, "%d, %d", index + 1,
    1026          40 :                                               bulk->rows_sent + 1);
    1027          40 :                                 return TDS_FAIL;
    1028         100 :                         case BLK_TRUNC_WARN:
    1029         100 :                                 _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 1, 2, 1, 42, "%d, %d", index + 1,
    1030         100 :                                               bulk->rows_sent + 1);
    1031         100 :                                 break;
    1032             :                         case BLK_TRUNC_SILENT:
    1033             :                                 break;
    1034             :                         }
    1035         130 :                         destlen = bindcol->on_server.column_size;
    1036             : 
    1037             :                         /* do not split bytes in hexadecimal representation of binary data */
    1038         190 :                         if (!binary_dest && _blk_is_binary_source(srctype)) {
    1039          20 :                                 int digit_size = is_unicode_type(bindcol->on_server.column_type) ? 2 : 1;
    1040             : 
    1041          20 :                                 destlen -= destlen % (digit_size * 2);
    1042             :                         }
    1043             :                 }
    1044             :         }
    1045             : 
    1046      125422 :         bindcol->bcp_column_data->datalen = destlen;
    1047      125422 :         bindcol->bcp_column_data->is_null = null_column;
    1048             : 
    1049      125422 :         return TDS_SUCCESS;
    1050             : }

Generated by: LCOV version 1.13