LCOV - code coverage report
Current view: top level - src/ctlib - blk.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 193 337 57.3 %
Date: 2025-01-18 11:50:39 Functions: 13 24 54.2 %

          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 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             : 
      46             : #define CONN(bulk) ((CS_CONNECTION *) (bulk)->bcpinfo.parent)
      47             : 
      48             : TDS_COMPILE_CHECK(same_size, sizeof(CS_BLKDESC) == sizeof(TDSBCPINFO));
      49             : TDS_COMPILE_CHECK(nested_type, TDS_OFFSET(CS_BLKDESC, bcpinfo) == 0);
      50             : 
      51             : CS_RETCODE
      52          32 : blk_alloc(CS_CONNECTION * connection, CS_INT version, CS_BLKDESC ** blk_pointer)
      53             : {
      54             :         CS_BLKDESC *blkdesc;
      55             : 
      56          32 :         tdsdump_log(TDS_DBG_FUNC, "blk_alloc(%p, %d, %p)\n", connection, version, blk_pointer);
      57             : 
      58          32 :         if (!connection || !connection->tds_socket)
      59             :                 return CS_FAIL;
      60             : 
      61          32 :         if (connection->tds_socket->conn->tds_version < 0x500)
      62             :                 return CS_FAIL;
      63             : 
      64          32 :         blkdesc = (CS_BLKDESC *) tds_alloc_bcpinfo();
      65          32 :         if (!blkdesc)
      66             :                 return CS_FAIL;
      67             : 
      68             :         /* so we know who we belong to */
      69          32 :         blkdesc->bcpinfo.parent = connection;
      70             : 
      71          32 :         *blk_pointer = blkdesc;
      72          32 :         return CS_SUCCEED;
      73             : }
      74             : 
      75             : 
      76             : CS_RETCODE
      77         320 : blk_bind(CS_BLKDESC * blkdesc, CS_INT item, CS_DATAFMT * datafmt_arg, CS_VOID * buffer, CS_INT * datalen, CS_SMALLINT * indicator)
      78             : {
      79             :         TDSCOLUMN *colinfo;
      80             :         CS_CONNECTION *con;
      81             :         CS_INT bind_count;
      82             :         const CS_DATAFMT_COMMON * datafmt;
      83             :         int i;
      84             : 
      85         320 :         tdsdump_log(TDS_DBG_FUNC, "blk_bind(%p, %d, %p, %p, %p, %p)\n", blkdesc, item, datafmt_arg, buffer, datalen, indicator);
      86             : 
      87         320 :         if (!blkdesc)
      88             :                 return CS_FAIL;
      89             : 
      90         320 :         con = CONN(blkdesc);
      91             : 
      92         320 :         datafmt = _ct_datafmt_common(con->ctx, datafmt_arg);
      93             : 
      94         320 :         if (item == CS_UNUSED) {
      95             :                 /* clear all bindings */
      96           0 :                 if (datafmt == NULL && buffer == NULL && datalen == NULL && indicator == NULL ) { 
      97           0 :                         blkdesc->bcpinfo.bind_count = CS_UNUSED;
      98           0 :                         for (i = 0; i < blkdesc->bcpinfo.bindinfo->num_cols; i++ ) {
      99           0 :                                 colinfo = blkdesc->bcpinfo.bindinfo->columns[i];
     100           0 :                                 colinfo->column_varaddr  = NULL;
     101           0 :                                 colinfo->column_bindtype = 0;
     102           0 :                                 colinfo->column_bindfmt  = 0;
     103           0 :                                 colinfo->column_bindlen  = 0;
     104           0 :                                 colinfo->column_nullbind = NULL;
     105           0 :                                 colinfo->column_lenbind  = NULL;
     106             :                         }
     107             :                 }
     108             :                 return CS_SUCCEED;
     109             :         }
     110             : 
     111             :         /* check item value */
     112             : 
     113         320 :         if (item < 1 || item > blkdesc->bcpinfo.bindinfo->num_cols) {
     114           0 :                 _ctclient_msg(NULL, con, "blk_bind", 2, 5, 1, 141, "%s, %d", "colnum", item);
     115           0 :                 return CS_FAIL;
     116             :         }
     117             : 
     118             :         /* clear bindings for this column */
     119             : 
     120         320 :         if (datafmt == NULL && buffer == NULL && datalen == NULL && indicator == NULL ) { 
     121             : 
     122           0 :                 colinfo = blkdesc->bcpinfo.bindinfo->columns[item - 1];
     123           0 :                 colinfo->column_varaddr  = NULL;
     124           0 :                 colinfo->column_bindtype = 0;
     125           0 :                 colinfo->column_bindfmt  = 0;
     126           0 :                 colinfo->column_bindlen  = 0;
     127           0 :                 colinfo->column_nullbind = NULL;
     128           0 :                 colinfo->column_lenbind  = NULL;
     129             : 
     130           0 :                 return CS_SUCCEED;
     131             :         }
     132             : 
     133         320 :         if (datafmt == NULL)
     134             :                 return CS_FAIL;
     135             : 
     136             :         /*
     137             :          * check whether the request is for array binding and ensure that user
     138             :          * supplies the same datafmt->count to the subsequent ct_bind calls
     139             :          */
     140             : 
     141         320 :         bind_count = (datafmt->count == 0) ? 1 : datafmt->count;
     142             : 
     143             :         /* first bind for this result set */
     144             : 
     145         320 :         if (blkdesc->bcpinfo.bind_count == CS_UNUSED) {
     146          96 :                 blkdesc->bcpinfo.bind_count = bind_count;
     147             :         } else {
     148             :                 /* all subsequent binds for this result set - the bind counts must be the same */
     149         224 :                 if (blkdesc->bcpinfo.bind_count != bind_count) {
     150           0 :                         _ctclient_msg(NULL, con, "blk_bind", 1, 1, 1, 137, "%d, %d", bind_count, blkdesc->bcpinfo.bind_count);
     151           0 :                         return CS_FAIL;
     152             :                 }
     153             :         }
     154             : 
     155             :         /* bind the column_varaddr to the address of the buffer */
     156             : 
     157         320 :         colinfo = blkdesc->bcpinfo.bindinfo->columns[item - 1];
     158             : 
     159         320 :         colinfo->column_varaddr = (char *) buffer;
     160         320 :         colinfo->column_bindtype = datafmt->datatype;
     161         320 :         colinfo->column_bindfmt = datafmt->format;
     162         320 :         colinfo->column_bindlen = datafmt->maxlength;
     163         320 :         if (indicator) {
     164         240 :                 colinfo->column_nullbind = indicator;
     165             :         }
     166         320 :         if (datalen) {
     167         320 :                 colinfo->column_lenbind = datalen;
     168             :         }
     169             :         return CS_SUCCEED;
     170             : }
     171             : 
     172             : CS_RETCODE
     173           0 : blk_colval(SRV_PROC * srvproc, CS_BLKDESC * blkdescp, CS_BLK_ROW * rowp, CS_INT colnum, CS_VOID * valuep, CS_INT valuelen,
     174             :            CS_INT * outlenp)
     175             : {
     176             : 
     177           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_colval(%p, %p, %p, %d, %p, %d, %p)\n", 
     178             :                                 srvproc, blkdescp, rowp, colnum, valuep, valuelen, outlenp);
     179             : 
     180           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_colval()\n");
     181           0 :         return CS_FAIL;
     182             : }
     183             : 
     184             : CS_RETCODE
     185           0 : blk_default(CS_BLKDESC * blkdesc, CS_INT colnum, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
     186             : {
     187             : 
     188           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_default(%p, %d, %p, %d, %p)\n", blkdesc, colnum, buffer, buflen, outlen);
     189             : 
     190           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_default()\n");
     191           0 :         return CS_FAIL;
     192             : }
     193             : 
     194             : CS_RETCODE
     195         240 : blk_describe(CS_BLKDESC * blkdesc, CS_INT item, CS_DATAFMT * datafmt_arg)
     196             : {
     197             :         TDSCOLUMN *curcol;
     198             :         CS_INT status, datatype;
     199             :         CS_DATAFMT_LARGE *datafmt;
     200             :         CS_DATAFMT_LARGE datafmt_buf;
     201             : 
     202         240 :         tdsdump_log(TDS_DBG_FUNC, "blk_describe(%p, %d, %p)\n", blkdesc, item, datafmt_arg);
     203             : 
     204         240 :         if (!blkdesc)
     205             :                 return CS_FAIL;
     206             : 
     207         240 :         datafmt = _ct_datafmt_conv_prepare(CONN(blkdesc)->ctx, datafmt_arg, &datafmt_buf);
     208             : 
     209         240 :         if (item < 1 || item > blkdesc->bcpinfo.bindinfo->num_cols) {
     210           0 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_describe", 2, 5, 1, 141, "%s, %d", "colnum", item);
     211           0 :                 return CS_FAIL;
     212             :         }
     213             : 
     214         240 :         curcol = blkdesc->bcpinfo.bindinfo->columns[item - 1];
     215             :         /* name is always null terminated */
     216         480 :         strlcpy(datafmt->name, tds_dstr_cstr(&curcol->column_name), sizeof(datafmt->name));
     217         240 :         datafmt->namelen = strlen(datafmt->name);
     218             :         /* need to turn the SYBxxx into a CS_xxx_TYPE */
     219         240 :         datatype = _ct_get_client_type(curcol, true);
     220         240 :         if (datatype == CS_ILLEGAL_TYPE)
     221             :                 return CS_FAIL;
     222         240 :         datafmt->datatype = datatype;
     223         240 :         tdsdump_log(TDS_DBG_INFO1, "blk_describe() datafmt->datatype = %d server type %d\n", datatype,
     224           0 :                         curcol->column_type);
     225             :         /* FIXME is ok this value for numeric/decimal? */
     226         240 :         datafmt->maxlength = curcol->column_size;
     227         240 :         datafmt->usertype = curcol->column_usertype;
     228         240 :         datafmt->precision = curcol->column_prec;
     229         240 :         datafmt->scale = curcol->column_scale;
     230             : 
     231             :         /*
     232             :          * There are other options that can be returned, but these are the
     233             :          * only two being noted via the TDS layer.
     234             :          */
     235         240 :         status = 0;
     236         240 :         if (curcol->column_nullable)
     237         112 :                 status |= CS_CANBENULL;
     238         240 :         if (curcol->column_identity)
     239           0 :                 status |= CS_IDENTITY;
     240         240 :         datafmt->status = status;
     241             : 
     242         240 :         datafmt->count = 1;
     243         240 :         datafmt->locale = NULL;
     244             : 
     245         240 :         _ct_datafmt_conv_back(datafmt_arg, datafmt);
     246         240 :         return CS_SUCCEED;
     247             : }
     248             : 
     249             : CS_RETCODE
     250          88 : blk_done(CS_BLKDESC * blkdesc, CS_INT type, CS_INT * outrow)
     251             : {
     252             :         TDSSOCKET *tds;
     253             :         int rows_copied;
     254             : 
     255          88 :         tdsdump_log(TDS_DBG_FUNC, "blk_done(%p, %d, %p)\n", blkdesc, type, outrow);
     256             : 
     257          88 :         tds = CONN(blkdesc)->tds_socket;
     258             : 
     259          88 :         switch (type) {
     260           0 :         case CS_BLK_BATCH:
     261           0 :                 if (TDS_FAILED(tds_bcp_done(tds, &rows_copied))) {
     262           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
     263           0 :                         return CS_FAIL;
     264             :                 }
     265             :                 
     266           0 :                 if (outrow) 
     267           0 :                         *outrow = rows_copied;
     268             :                 
     269           0 :                 if (TDS_FAILED(tds_bcp_start(tds, &blkdesc->bcpinfo))) {
     270           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
     271           0 :                         return CS_FAIL;
     272             :                 }
     273             :                 break;
     274             :                 
     275          88 :         case CS_BLK_ALL:
     276          88 :                 if (TDS_FAILED(tds_bcp_done(tds, &rows_copied))) {
     277           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
     278           0 :                         return CS_FAIL;
     279             :                 }
     280             :                 
     281          88 :                 if (outrow) 
     282          88 :                         *outrow = rows_copied;
     283             :                 
     284             :                 /* free allocated storage in blkdesc & initialise flags, etc. */
     285          88 :                 tds_deinit_bcpinfo(&blkdesc->bcpinfo);
     286             :         
     287          88 :                 blkdesc->bcpinfo.direction = 0;
     288          88 :                 blkdesc->bcpinfo.bind_count = CS_UNUSED;
     289          88 :                 blkdesc->bcpinfo.xfer_init = 0;
     290             : 
     291          88 :                 break;
     292             : 
     293             :         }
     294             : 
     295             :         return CS_SUCCEED;
     296             : }
     297             : 
     298             : CS_RETCODE
     299          32 : blk_drop(CS_BLKDESC * blkdesc)
     300             : {
     301          32 :         tdsdump_log(TDS_DBG_FUNC, "blk_drop(%p)\n", blkdesc);
     302             : 
     303             :         /* this is possible as CS_BLKDESC contains just bcpinfo field */
     304          32 :         tds_free_bcpinfo(&blkdesc->bcpinfo);
     305             : 
     306          32 :         return CS_SUCCEED;
     307             : }
     308             : 
     309             : CS_RETCODE
     310           0 : blk_getrow(SRV_PROC * srvproc, CS_BLKDESC * blkdescp, CS_BLK_ROW * rowp)
     311             : {
     312           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_getrow(%p, %p, %p)\n", srvproc, blkdescp, rowp);
     313             : 
     314           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_getrow()\n");
     315           0 :         return CS_FAIL;
     316             : }
     317             : 
     318             : CS_RETCODE
     319           0 : blk_gettext(SRV_PROC * srvproc, CS_BLKDESC * blkdescp, CS_BLK_ROW * rowp, CS_INT bufsize, CS_INT * outlenp)
     320             : {
     321             : 
     322           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_gettext(%p, %p, %p, %d, %p)\n", srvproc, blkdescp, rowp, bufsize, outlenp);
     323             : 
     324           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_gettext()\n");
     325           0 :         return CS_FAIL;
     326             : }
     327             : 
     328             : CS_RETCODE
     329         120 : blk_init(CS_BLKDESC * blkdesc, CS_INT direction, CS_CHAR * tablename, CS_INT tnamelen)
     330             : {
     331         120 :         tdsdump_log(TDS_DBG_FUNC, "blk_init(%p, %d, %p, %d)\n", blkdesc, direction, tablename, tnamelen);
     332             : 
     333         120 :         if (!blkdesc) {
     334             :                 return CS_FAIL;
     335             :         }
     336             : 
     337         120 :         if (direction != CS_BLK_IN && direction != CS_BLK_OUT ) {
     338           8 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 15, "");
     339           8 :                 return CS_FAIL;
     340             :         }
     341             : 
     342         112 :         if (!tablename) {
     343           8 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 6, "tblname");
     344           8 :                 return CS_FAIL;
     345             :         }
     346         104 :         tnamelen = _ct_get_string_length(tablename, tnamelen);
     347         104 :         if (tnamelen < 0) {
     348           8 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 4, "tblnamelen, %d", tnamelen);
     349           8 :                 return CS_FAIL;
     350             :         }
     351             : 
     352             :         /* free allocated storage in blkdesc & initialise flags, etc. */
     353          96 :         tds_deinit_bcpinfo(&blkdesc->bcpinfo);
     354             : 
     355             :         /* string can be no-nul terminated so copy with memcpy */
     356          96 :         if (!tds_dstr_copyn(&blkdesc->bcpinfo.tablename, tablename, tnamelen)) {
     357             :                 return CS_FAIL;
     358             :         }
     359             : 
     360          96 :         blkdesc->bcpinfo.direction = direction;
     361          96 :         blkdesc->bcpinfo.bind_count = CS_UNUSED;
     362          96 :         blkdesc->bcpinfo.xfer_init = 0;
     363             : 
     364          96 :         if (TDS_FAILED(tds_bcp_init(CONN(blkdesc)->tds_socket, &blkdesc->bcpinfo))) {
     365           0 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 2, 5, 1, 140, "");
     366           0 :                 return CS_FAIL;
     367             :         }
     368          96 :         blkdesc->bcpinfo.bind_count = CS_UNUSED;
     369             : 
     370          96 :         return CS_SUCCEED;
     371             : }
     372             : 
     373             : CS_RETCODE
     374          80 : blk_props(CS_BLKDESC * blkdesc, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
     375             : {
     376             :         int retval, intval;
     377             : 
     378          80 :         tdsdump_log(TDS_DBG_FUNC, "blk_props(%p, %d, %d, %p, %d, %p)\n", blkdesc, action, property, buffer, buflen, outlen);
     379             : 
     380          80 :         switch (property) {
     381           0 :         case BLK_IDENTITY: 
     382           0 :                 switch (action) {
     383           0 :                 case CS_SET: 
     384           0 :                         if (buffer) {
     385           0 :                                 memcpy(&intval, buffer, sizeof(intval));
     386           0 :                                 if (intval == CS_TRUE)
     387           0 :                                         blkdesc->bcpinfo.identity_insert_on = 1;
     388           0 :                                 if (intval == CS_FALSE)
     389           0 :                                         blkdesc->bcpinfo.identity_insert_on = 0;
     390             :                         }
     391             :                         return CS_SUCCEED;
     392             :                         break;
     393           0 :                 case CS_GET:
     394           0 :                         retval = blkdesc->bcpinfo.identity_insert_on == 1 ? CS_TRUE : CS_FALSE ;
     395           0 :                         if (buffer) {
     396           0 :                                 memcpy (buffer, &retval, sizeof(retval));
     397           0 :                                 if (outlen)
     398           0 :                                         *outlen = sizeof(retval);
     399             :                         }
     400             :                         return CS_SUCCEED;
     401             :                         break;
     402           0 :                 default:
     403           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_props", 2, 5, 1, 141, "%s, %d", "action", action);
     404             :                         break;
     405             :                 }
     406           0 :                 break;
     407             : 
     408          80 :         case BLK_HINTS:
     409          80 :                 return _ct_props_dstr(CONN(blkdesc), &blkdesc->bcpinfo.hint, action, buffer, buflen, outlen);
     410             : 
     411           0 :         default:
     412           0 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_props", 2, 5, 1, 141, "%s, %d", "property", property);
     413           0 :                 break;
     414             :         }
     415             :         return CS_FAIL;
     416             : }
     417             : 
     418             : CS_RETCODE
     419           0 : blk_rowalloc(SRV_PROC * srvproc, CS_BLK_ROW ** row)
     420             : {
     421           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_rowalloc(%p, %p)\n", srvproc, row);
     422             : 
     423           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_rowalloc()\n");
     424           0 :         return CS_FAIL;
     425             : }
     426             : 
     427             : CS_RETCODE
     428           0 : blk_rowdrop(SRV_PROC * srvproc, CS_BLK_ROW * row)
     429             : {
     430           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_rowdrop(%p, %p)\n", srvproc, row);
     431             : 
     432           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_rowdrop()\n");
     433           0 :         return CS_FAIL;
     434             : }
     435             : 
     436             : CS_RETCODE
     437         160 : blk_rowxfer(CS_BLKDESC * blkdesc)
     438             : {
     439         160 :         tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer(%p)\n", blkdesc);
     440             : 
     441         160 :         return blk_rowxfer_mult(blkdesc, NULL);
     442             : }
     443             : 
     444             : CS_RETCODE
     445         184 : blk_rowxfer_mult(CS_BLKDESC * blkdesc, CS_INT * row_count)
     446             : {
     447         184 :         CS_INT rows_to_xfer = 0;
     448         184 :         CS_INT rows_xferred = 0;
     449             :         CS_RETCODE ret;
     450             : 
     451         184 :         tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_mult(%p, %p)\n", blkdesc, row_count);
     452             : 
     453         184 :         if (!row_count || *row_count == 0 )
     454         168 :                 rows_to_xfer = blkdesc->bcpinfo.bind_count;
     455             :         else
     456             :                 rows_to_xfer = *row_count;
     457             : 
     458         184 :         if (blkdesc->bcpinfo.direction == CS_BLK_IN) {
     459         160 :                 ret = _blk_rowxfer_in(blkdesc, rows_to_xfer, &rows_xferred);
     460             :         } else {
     461          24 :                 ret = _blk_rowxfer_out(blkdesc, rows_to_xfer, &rows_xferred);
     462             :         }
     463         184 :         if (row_count)
     464          24 :                 *row_count = rows_xferred;
     465         184 :         return ret;
     466             : 
     467             : }
     468             : 
     469             : CS_RETCODE
     470           0 : blk_sendrow(CS_BLKDESC * blkdesc, CS_BLK_ROW * row)
     471             : {
     472             : 
     473           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_sendrow(%p, %p)\n", blkdesc, row);
     474             : 
     475           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_sendrow()\n");
     476           0 :         return CS_FAIL;
     477             : }
     478             : 
     479             : CS_RETCODE
     480           0 : blk_sendtext(CS_BLKDESC * blkdesc, CS_BLK_ROW * row, CS_BYTE * buffer, CS_INT buflen)
     481             : {
     482           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_sendtext(%p, %p, %p, %d)\n", blkdesc, row, buffer, buflen);
     483             : 
     484           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_sendtext()\n");
     485           0 :         return CS_FAIL;
     486             : }
     487             : 
     488             : CS_RETCODE
     489           0 : blk_srvinit(SRV_PROC * srvproc, CS_BLKDESC * blkdescp)
     490             : {
     491           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_srvinit(%p, %p)\n", srvproc, blkdescp);
     492             : 
     493           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_srvinit()\n");
     494           0 :         return CS_FAIL;
     495             : }
     496             : 
     497             : CS_RETCODE
     498           0 : blk_textxfer(CS_BLKDESC * blkdesc, CS_BYTE * buffer, CS_INT buflen, CS_INT * outlen)
     499             : {
     500           0 :         tdsdump_log(TDS_DBG_FUNC, "blk_textxfer(%p, %p, %d, %p)\n", blkdesc, buffer, buflen, outlen);
     501             : 
     502           0 :         tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_textxfer()\n");
     503           0 :         return CS_FAIL;
     504             : }
     505             : 
     506             : static CS_RETCODE
     507          24 : _blk_rowxfer_out(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred)
     508             : {
     509             :         TDSSOCKET *tds;
     510             :         TDS_INT result_type;
     511             :         TDSRET ret;
     512             :         TDS_INT temp_count;
     513             : 
     514          24 :         tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_out(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
     515             : 
     516          24 :         if (!blkdesc || !CONN(blkdesc))
     517             :                 return CS_FAIL;
     518             : 
     519          24 :         tds = CONN(blkdesc)->tds_socket;
     520             : 
     521             :         /*
     522             :          * the first time blk_xfer called after blk_init()
     523             :          * do the query and get to the row data...
     524             :          */
     525             : 
     526          24 :         if (blkdesc->bcpinfo.xfer_init == 0) {
     527             : 
     528          16 :                 if (TDS_FAILED(tds_submit_queryf(tds, "select * from %s", tds_dstr_cstr(&blkdesc->bcpinfo.tablename)))) {
     529           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
     530           0 :                         return CS_FAIL;
     531             :                 }
     532             : 
     533          16 :                 while ((ret = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
     534          16 :                         if (result_type == TDS_ROW_RESULT)
     535             :                                 break;
     536             :                 }
     537             :         
     538           8 :                 if (ret != TDS_SUCCESS || result_type != TDS_ROW_RESULT) {
     539           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
     540           0 :                         return CS_FAIL;
     541             :                 }
     542             : 
     543           8 :                 blkdesc->bcpinfo.xfer_init = 1;
     544             :         }
     545             : 
     546          24 :         if (rows_xferred)
     547          24 :                 *rows_xferred = 0;
     548             : 
     549          40 :         for (temp_count = 0; temp_count < rows_to_xfer; temp_count++) {
     550             : 
     551          48 :                 ret = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
     552             : 
     553          48 :                 tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_out() process_row_tokens returned %d\n", ret);
     554             : 
     555          48 :                 switch (ret) {
     556          48 :                 case TDS_SUCCESS:
     557          48 :                         if (result_type == TDS_ROW_RESULT || result_type == TDS_COMPUTE_RESULT) {
     558          40 :                                 if (result_type == TDS_ROW_RESULT) {
     559          40 :                                         if (_ct_bind_data( CONN(blkdesc)->ctx, tds->current_results, blkdesc->bcpinfo.bindinfo, temp_count))
     560             :                                                 return CS_ROW_FAIL;
     561          40 :                                         if (rows_xferred)
     562          40 :                                                 *rows_xferred = *rows_xferred + 1;
     563             :                                 }
     564             :                                 break;
     565             :                         }
     566             :                 case TDS_NO_MORE_RESULTS: 
     567             :                         return CS_END_DATA;
     568             :                         break;
     569             : 
     570           0 :                 default:
     571           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
     572           0 :                         return CS_FAIL;
     573             :                         break;
     574             :                 }
     575             :         } 
     576             : 
     577             :         return CS_SUCCEED;
     578             : }
     579             : 
     580             : static CS_RETCODE
     581         160 : _blk_rowxfer_in(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred)
     582             : {
     583             :         TDSSOCKET *tds;
     584             :         TDS_INT each_row;
     585             : 
     586         160 :         tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_in(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
     587             : 
     588         160 :         if (!blkdesc)
     589             :                 return CS_FAIL;
     590             : 
     591         160 :         tds = CONN(blkdesc)->tds_socket;
     592             : 
     593             :         /*
     594             :          * the first time blk_xfer called after blk_init()
     595             :          * do the query and get to the row data...
     596             :          */
     597             : 
     598         160 :         if (blkdesc->bcpinfo.xfer_init == 0) {
     599             : 
     600             :                 /*
     601             :                  * first call the start_copy function, which will
     602             :                  * retrieve details of the database table columns
     603             :                  */
     604             : 
     605          88 :                 if (TDS_FAILED(tds_bcp_start_copy_in(tds, &blkdesc->bcpinfo))) {
     606           0 :                         _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
     607           0 :                         return CS_FAIL;
     608             :                 }
     609             : 
     610          88 :                 blkdesc->bcpinfo.xfer_init = 1;
     611             :         } 
     612             : 
     613         160 :         for (each_row = 0; each_row < rows_to_xfer; each_row++ ) {
     614             : 
     615         160 :                 if (tds_bcp_send_record(tds, &blkdesc->bcpinfo, _blk_get_col_data, _blk_null_error, each_row) == TDS_SUCCESS) {
     616             :                         /* FIXME */
     617             :                 }
     618             :         }
     619             : 
     620             :         return CS_SUCCEED;
     621             : }
     622             : 
     623             : static void
     624           0 : _blk_null_error(TDSBCPINFO *bcpinfo, int index, int offset)
     625             : {
     626           0 :         CS_BLKDESC *blkdesc = (CS_BLKDESC *) bcpinfo;
     627             : 
     628           0 :         tdsdump_log(TDS_DBG_FUNC, "_blk_null_error(%p, %d, %d)\n", bcpinfo, index, offset);
     629             : 
     630           0 :         _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 7, 1, 142, "%d, %d",  index + 1, offset + 1);
     631           0 : }
     632             : 
     633             : static TDS_INT _blk_to_not_client(CS_CONTEXT *ctx, TDSCOLUMN *col, const CS_DATAFMT_COMMON * srcfmt, CS_VOID * srcdata);
     634             : 
     635             : static TDSRET
     636        2240 : _blk_get_col_data(TDSBCPINFO *bulk, TDSCOLUMN *bindcol, int offset)
     637             : {
     638        2240 :         int result = 0;
     639        2240 :         bool null_column = false;
     640        2240 :         unsigned char *src = NULL;
     641             : 
     642        2240 :         CS_INT      srctype = 0;
     643        2240 :         CS_INT      srclen  = 0;
     644        2240 :         CS_INT      destlen  = 0;
     645        2240 :         CS_SMALLINT *nullind = NULL;
     646        2240 :         CS_INT      *datalen = NULL;
     647        2240 :         CS_BLKDESC *blkdesc = (CS_BLKDESC *) bulk;
     648        2240 :         CS_CONTEXT *ctx = CONN(blkdesc)->ctx;
     649             : 
     650        2240 :         tdsdump_log(TDS_DBG_FUNC, "_blk_get_col_data(%p, %p, %d)\n", bulk, bindcol, offset);
     651             : 
     652             :         /*
     653             :          * Retrieve the initial bound column_varaddress
     654             :          * and increment it if offset specified
     655             :          */
     656             : 
     657        2240 :         src = (unsigned char *) bindcol->column_varaddr;
     658        2240 :         if (!src) {
     659           0 :                 tdsdump_log(TDS_DBG_ERROR, "error source field not addressable\n");
     660             :                 return TDS_FAIL;
     661             :         }
     662             : 
     663        2240 :         src += offset * bindcol->column_bindlen;
     664             :         
     665        2240 :         if (bindcol->column_nullbind) {
     666        2160 :                 nullind = bindcol->column_nullbind;
     667        2160 :                 nullind += offset;
     668             :         }
     669        2240 :         if (bindcol->column_lenbind) {
     670        2240 :                 datalen = bindcol->column_lenbind;
     671        2240 :                 datalen += offset;
     672             :         }
     673             : 
     674        2240 :         srctype = bindcol->column_bindtype;          /* passes to cs_convert */
     675             : 
     676        2240 :         tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data srctype = %d\n", srctype);
     677        2240 :         tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data datalen = %d\n", datalen ? *datalen : -1);
     678             : 
     679        2240 :         if (datalen) {
     680        2240 :                 if (*datalen == CS_UNUSED) {
     681           0 :                         switch (srctype) {
     682             :                         case CS_LONG_TYPE:          srclen = 8; break;
     683             :                         case CS_FLOAT_TYPE:         srclen = 8; break;
     684             :                         case CS_MONEY_TYPE:         srclen = 8; break;
     685             :                         case CS_DATETIME_TYPE:  srclen = 8; break;
     686           0 :                         case CS_INT_TYPE:           srclen = 4; break;
     687           0 :                         case CS_UINT_TYPE:          srclen = 4; break;
     688           0 :                         case CS_REAL_TYPE:          srclen = 4; break;
     689           0 :                         case CS_MONEY4_TYPE:    srclen = 4; break;
     690           0 :                         case CS_DATETIME4_TYPE: srclen = 4; break;
     691           0 :                         case CS_SMALLINT_TYPE:  srclen = 2; break;
     692           0 :                         case CS_USMALLINT_TYPE:  srclen = 2; break;
     693           0 :                         case CS_TINYINT_TYPE:   srclen = 1; break;
     694           0 :                         case CS_BIT_TYPE:   srclen = 1; break;
     695             :                         case CS_BIGINT_TYPE:        srclen = 8; break;
     696             :                         case CS_UBIGINT_TYPE:       srclen = 8; break;
     697           0 :                         case CS_UNIQUE_TYPE:        srclen = 16; break;
     698           0 :                         default:
     699           0 :                                 tdsdump_log(TDS_DBG_ERROR, "Not fixed length type (%d) and datalen not specified\n",
     700           0 :                                             bindcol->column_bindtype);
     701             :                                 return TDS_FAIL;
     702             :                         }
     703             : 
     704             :                 } else {
     705        2240 :                         srclen = *datalen;
     706             :                 }
     707             :         }
     708        2240 :         if (srclen == 0) {
     709        1040 :                 if (nullind && *nullind == -1)
     710             :                         null_column = true;
     711             :         }
     712             : 
     713             :         if (!null_column) {
     714             :                 CS_DATAFMT_COMMON srcfmt, destfmt;
     715             :                 CS_INT desttype;
     716             :                 TDS_INT outlen;
     717             : 
     718        1200 :                 srcfmt.datatype = srctype;
     719        1200 :                 srcfmt.maxlength = srclen;
     720             : 
     721        1200 :                 outlen = _blk_to_not_client(ctx, bindcol, &srcfmt, src);
     722        1200 :                 if (outlen != TDS_CONVERT_NOAVAIL)
     723           0 :                         return outlen > 0 ? TDS_SUCCESS : TDS_FAIL;
     724             : 
     725        1200 :                 desttype = _ct_get_client_type(bindcol, false);
     726        1200 :                 if (desttype == CS_ILLEGAL_TYPE)
     727             :                         return TDS_FAIL;
     728        1200 :                 destfmt.datatype  = desttype;
     729        1200 :                 destfmt.maxlength = bindcol->on_server.column_size;
     730        1200 :                 destfmt.precision = bindcol->column_prec;
     731        1200 :                 destfmt.scale     = bindcol->column_scale;
     732        1200 :                 destfmt.format    = CS_FMT_UNUSED;
     733             : 
     734             :                 /* if convert return FAIL mark error but process other columns */
     735        1200 :                 if ((result = _cs_convert(ctx, &srcfmt, (CS_VOID *) src,
     736        1200 :                                          &destfmt, (CS_VOID *) bindcol->bcp_column_data->data, &destlen)) != CS_SUCCEED) {
     737           0 :                         tdsdump_log(TDS_DBG_ERROR, "conversion from srctype %d to desttype %d failed\n",
     738             :                                     srctype, desttype);
     739             :                         return TDS_FAIL;
     740             :                 }
     741             :         }
     742             : 
     743        2240 :         bindcol->bcp_column_data->datalen = destlen;
     744        2240 :         bindcol->bcp_column_data->is_null = null_column;
     745             : 
     746        2240 :         return TDS_SUCCESS;
     747             : }
     748             : 
     749             : static TDS_INT
     750        1200 : _blk_to_not_client(CS_CONTEXT *ctx, TDSCOLUMN *col, const CS_DATAFMT_COMMON * srcfmt, CS_VOID * srcdata)
     751             : {
     752        1200 :         TDS_SERVER_TYPE desttype = col->on_server.column_type, srctype;
     753             :         CS_INT datatype, src_len;
     754             :         TDS_INT out_len;
     755             : 
     756        1200 :         switch (desttype) {
     757             :         case SYBMSDATE:
     758             :         case SYBMSTIME:
     759             :         case SYBMSDATETIME2:
     760             :         case SYBMSDATETIMEOFFSET:
     761             :                 break;
     762             :         default:
     763             :                 return TDS_CONVERT_NOAVAIL;
     764             :         }
     765             : 
     766           0 :         datatype = srcfmt->datatype;
     767           0 :         srctype = _ct_get_server_type(NULL, datatype);
     768           0 :         if (srctype == TDS_INVALID_TYPE)
     769             :                 return TDS_CONVERT_FAIL;
     770             : 
     771           0 :         src_len = srcfmt->maxlength;
     772           0 :         if (datatype == CS_VARCHAR_TYPE || datatype == CS_VARBINARY_TYPE) {
     773           0 :                 CS_VARCHAR *vc = (CS_VARCHAR *) srcdata;
     774           0 :                 src_len = vc->len;
     775           0 :                 srcdata = vc->str;
     776             :         }
     777             : 
     778           0 :         out_len = tds_convert(ctx->tds_ctx, srctype, srcdata,
     779           0 :                               src_len, desttype, (CONV_RESULT *) col->bcp_column_data->data);
     780           0 :         if (out_len < 0)
     781             :                 return out_len;
     782             : 
     783           0 :         col->bcp_column_data->datalen = out_len;
     784           0 :         col->bcp_column_data->is_null = false;
     785             : 
     786             :         return out_len;
     787             : }

Generated by: LCOV version 1.13