LCOV - code coverage report
Current view: top level - src/ctlib - blk.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 192 324 59.3 %
Date: 2025-04-13 14:39:30 Functions: 12 23 52.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          50 : blk_alloc(CS_CONNECTION * connection, CS_INT version, CS_BLKDESC ** blk_pointer)
      53             : {
      54             :         CS_BLKDESC *blkdesc;
      55             : 
      56          50 :         tdsdump_log(TDS_DBG_FUNC, "blk_alloc(%p, %d, %p)\n", connection, version, blk_pointer);
      57             : 
      58          50 :         if (!connection || !connection->tds_socket)
      59             :                 return CS_FAIL;
      60             : 
      61          50 :         if (connection->tds_socket->conn->tds_version < 0x500)
      62             :                 return CS_FAIL;
      63             : 
      64          50 :         blkdesc = (CS_BLKDESC *) tds_alloc_bcpinfo();
      65          50 :         if (!blkdesc)
      66             :                 return CS_FAIL;
      67             : 
      68             :         /* so we know who we belong to */
      69          50 :         blkdesc->bcpinfo.parent = connection;
      70             : 
      71          50 :         *blk_pointer = blkdesc;
      72          50 :         return CS_SUCCEED;
      73             : }
      74             : 
      75             : 
      76             : CS_RETCODE
      77         410 : 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         410 :         tdsdump_log(TDS_DBG_FUNC, "blk_bind(%p, %d, %p, %p, %p, %p)\n", blkdesc, item, datafmt_arg, buffer, datalen, indicator);
      86             : 
      87         410 :         if (!blkdesc)
      88             :                 return CS_FAIL;
      89             : 
      90         410 :         con = CONN(blkdesc);
      91             : 
      92         410 :         datafmt = _ct_datafmt_common(con->ctx, datafmt_arg);
      93             : 
      94         410 :         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         410 :         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         410 :         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         410 :         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         410 :         bind_count = (datafmt->count == 0) ? 1 : datafmt->count;
     142             : 
     143             :         /* first bind for this result set */
     144             : 
     145         410 :         if (blkdesc->bcpinfo.bind_count == CS_UNUSED) {
     146         130 :                 blkdesc->bcpinfo.bind_count = bind_count;
     147             :         } else {
     148             :                 /* all subsequent binds for this result set - the bind counts must be the same */
     149         280 :                 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         410 :         colinfo = blkdesc->bcpinfo.bindinfo->columns[item - 1];
     158             : 
     159         410 :         colinfo->column_varaddr = (char *) buffer;
     160         410 :         colinfo->column_bindtype = datafmt->datatype;
     161         410 :         colinfo->column_bindfmt = datafmt->format;
     162         410 :         colinfo->column_bindlen = datafmt->maxlength;
     163         410 :         if (indicator) {
     164         310 :                 colinfo->column_nullbind = indicator;
     165             :         }
     166         410 :         if (datalen) {
     167         410 :                 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         310 : 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         310 :         tdsdump_log(TDS_DBG_FUNC, "blk_describe(%p, %d, %p)\n", blkdesc, item, datafmt_arg);
     203             : 
     204         310 :         if (!blkdesc)
     205             :                 return CS_FAIL;
     206             : 
     207         310 :         datafmt = _ct_datafmt_conv_prepare(CONN(blkdesc)->ctx, datafmt_arg, &datafmt_buf);
     208             : 
     209         310 :         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         310 :         curcol = blkdesc->bcpinfo.bindinfo->columns[item - 1];
     215             :         /* name is always null terminated */
     216         620 :         strlcpy(datafmt->name, tds_dstr_cstr(&curcol->column_name), sizeof(datafmt->name));
     217         310 :         datafmt->namelen = (CS_INT) strlen(datafmt->name);
     218             :         /* need to turn the SYBxxx into a CS_xxx_TYPE */
     219         310 :         datatype = _ct_get_client_type(curcol, true);
     220         310 :         if (datatype == CS_ILLEGAL_TYPE)
     221             :                 return CS_FAIL;
     222         310 :         datafmt->datatype = datatype;
     223         310 :         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         310 :         datafmt->maxlength = curcol->column_size;
     227         310 :         datafmt->usertype = curcol->column_usertype;
     228         310 :         datafmt->precision = curcol->column_prec;
     229         310 :         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         310 :         status = 0;
     236         310 :         if (curcol->column_nullable)
     237         140 :                 status |= CS_CANBENULL;
     238         310 :         if (curcol->column_identity)
     239           0 :                 status |= CS_IDENTITY;
     240         310 :         datafmt->status = status;
     241             : 
     242         310 :         datafmt->count = 1;
     243         310 :         datafmt->locale = NULL;
     244             : 
     245         310 :         _ct_datafmt_conv_back(datafmt_arg, datafmt);
     246         310 :         return CS_SUCCEED;
     247             : }
     248             : 
     249             : CS_RETCODE
     250         120 : blk_done(CS_BLKDESC * blkdesc, CS_INT type, CS_INT * outrow)
     251             : {
     252             :         TDSSOCKET *tds;
     253             :         int rows_copied;
     254             : 
     255         120 :         tdsdump_log(TDS_DBG_FUNC, "blk_done(%p, %d, %p)\n", blkdesc, type, outrow);
     256             : 
     257         120 :         tds = CONN(blkdesc)->tds_socket;
     258             : 
     259         120 :         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         120 :         case CS_BLK_ALL:
     276         120 :                 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         120 :                 if (outrow) 
     282         120 :                         *outrow = rows_copied;
     283             :                 
     284             :                 /* free allocated storage in blkdesc & initialise flags, etc. */
     285         120 :                 tds_deinit_bcpinfo(&blkdesc->bcpinfo);
     286             :         
     287         120 :                 blkdesc->bcpinfo.direction = 0;
     288         120 :                 blkdesc->bcpinfo.bind_count = CS_UNUSED;
     289         120 :                 blkdesc->bcpinfo.xfer_init = false;
     290             : 
     291         120 :                 break;
     292             : 
     293             :         }
     294             : 
     295             :         return CS_SUCCEED;
     296             : }
     297             : 
     298             : CS_RETCODE
     299          50 : blk_drop(CS_BLKDESC * blkdesc)
     300             : {
     301          50 :         tdsdump_log(TDS_DBG_FUNC, "blk_drop(%p)\n", blkdesc);
     302             : 
     303             :         /* this is possible as CS_BLKDESC contains just bcpinfo field */
     304          50 :         tds_free_bcpinfo(&blkdesc->bcpinfo);
     305             : 
     306          50 :         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         160 : blk_init(CS_BLKDESC * blkdesc, CS_INT direction, CS_CHAR * tablename, CS_INT tnamelen)
     330             : {
     331         160 :         tdsdump_log(TDS_DBG_FUNC, "blk_init(%p, %d, %p, %d)\n", blkdesc, direction, tablename, tnamelen);
     332             : 
     333         160 :         if (!blkdesc) {
     334             :                 return CS_FAIL;
     335             :         }
     336             : 
     337         160 :         if (direction != CS_BLK_IN && direction != CS_BLK_OUT ) {
     338          10 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 15, "");
     339          10 :                 return CS_FAIL;
     340             :         }
     341             : 
     342         150 :         if (!tablename) {
     343          10 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 6, "tblname");
     344          10 :                 return CS_FAIL;
     345             :         }
     346         140 :         tnamelen = _ct_get_string_length(tablename, tnamelen);
     347         140 :         if (tnamelen < 0) {
     348          10 :                 _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 4, "tblnamelen, %d", tnamelen);
     349          10 :                 return CS_FAIL;
     350             :         }
     351             : 
     352             :         /* free allocated storage in blkdesc & initialise flags, etc. */
     353         130 :         tds_deinit_bcpinfo(&blkdesc->bcpinfo);
     354             : 
     355             :         /* string can be no-nul terminated so copy with memcpy */
     356         130 :         if (!tds_dstr_copyn(&blkdesc->bcpinfo.tablename, tablename, tnamelen)) {
     357             :                 return CS_FAIL;
     358             :         }
     359             : 
     360         130 :         blkdesc->bcpinfo.direction = direction;
     361         130 :         blkdesc->bcpinfo.bind_count = CS_UNUSED;
     362         130 :         blkdesc->bcpinfo.xfer_init = false;
     363             : 
     364         130 :         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         130 :         blkdesc->bcpinfo.bind_count = CS_UNUSED;
     369             : 
     370         130 :         return CS_SUCCEED;
     371             : }
     372             : 
     373             : CS_RETCODE
     374         100 : 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         100 :         tdsdump_log(TDS_DBG_FUNC, "blk_props(%p, %d, %d, %p, %d, %p)\n", blkdesc, action, property, buffer, buflen, outlen);
     379             : 
     380         100 :         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 = true;
     388           0 :                                 if (intval == CS_FALSE)
     389           0 :                                         blkdesc->bcpinfo.identity_insert_on = false;
     390             :                         }
     391             :                         return CS_SUCCEED;
     392             :                         break;
     393           0 :                 case CS_GET:
     394           0 :                         retval = blkdesc->bcpinfo.identity_insert_on ? 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         100 :         case BLK_HINTS:
     409         100 :                 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         300 : blk_rowxfer(CS_BLKDESC * blkdesc)
     438             : {
     439         300 :         tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer(%p)\n", blkdesc);
     440             : 
     441         300 :         return blk_rowxfer_mult(blkdesc, NULL);
     442             : }
     443             : 
     444             : CS_RETCODE
     445         330 : blk_rowxfer_mult(CS_BLKDESC * blkdesc, CS_INT * row_count)
     446             : {
     447         330 :         CS_INT rows_to_xfer = 0;
     448         330 :         CS_INT rows_xferred = 0;
     449             :         CS_RETCODE ret;
     450             : 
     451         330 :         tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_mult(%p, %p)\n", blkdesc, row_count);
     452             : 
     453         330 :         if (!row_count || *row_count == 0 )
     454         310 :                 rows_to_xfer = blkdesc->bcpinfo.bind_count;
     455             :         else
     456             :                 rows_to_xfer = *row_count;
     457             : 
     458         330 :         if (blkdesc->bcpinfo.direction == CS_BLK_IN) {
     459         300 :                 ret = _blk_rowxfer_in(blkdesc, rows_to_xfer, &rows_xferred);
     460             :         } else {
     461          30 :                 ret = _blk_rowxfer_out(blkdesc, rows_to_xfer, &rows_xferred);
     462             :         }
     463         330 :         if (row_count)
     464          30 :                 *row_count = rows_xferred;
     465         330 :         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          30 : _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          30 :         tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_out(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
     515             : 
     516          30 :         if (!blkdesc || !CONN(blkdesc))
     517             :                 return CS_FAIL;
     518             : 
     519          30 :         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          30 :         if (!blkdesc->bcpinfo.xfer_init) {
     527             : 
     528          20 :                 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          20 :                 while ((ret = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
     534          20 :                         if (result_type == TDS_ROW_RESULT)
     535             :                                 break;
     536             :                 }
     537             :         
     538          10 :                 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          10 :                 blkdesc->bcpinfo.xfer_init = true;
     544             :         }
     545             : 
     546          30 :         if (rows_xferred)
     547          30 :                 *rows_xferred = 0;
     548             : 
     549          50 :         for (temp_count = 0; temp_count < rows_to_xfer; temp_count++) {
     550             : 
     551          60 :                 ret = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
     552             : 
     553          60 :                 tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_out() process_row_tokens returned %d\n", ret);
     554             : 
     555          60 :                 switch (ret) {
     556          60 :                 case TDS_SUCCESS:
     557          60 :                         if (result_type == TDS_ROW_RESULT || result_type == TDS_COMPUTE_RESULT) {
     558          50 :                                 if (result_type == TDS_ROW_RESULT) {
     559          50 :                                         if (_ct_bind_data( CONN(blkdesc)->ctx, tds->current_results, blkdesc->bcpinfo.bindinfo, temp_count))
     560             :                                                 return CS_ROW_FAIL;
     561          50 :                                         if (rows_xferred)
     562          50 :                                                 *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         300 : _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         300 :         tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_in(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
     587             : 
     588         300 :         if (!blkdesc)
     589             :                 return CS_FAIL;
     590             : 
     591         300 :         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         300 :         if (!blkdesc->bcpinfo.xfer_init) {
     599             : 
     600             :                 /*
     601             :                  * first call the start_copy function, which will
     602             :                  * retrieve details of the database table columns
     603             :                  */
     604             : 
     605         120 :                 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         120 :                 blkdesc->bcpinfo.xfer_init = true;
     611             :         } 
     612             : 
     613         300 :         for (each_row = 0; each_row < rows_to_xfer; each_row++ ) {
     614             : 
     615         300 :                 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 TDSRET
     634        2900 : _blk_get_col_data(TDSBCPINFO *bulk, TDSCOLUMN *bindcol, int offset)
     635             : {
     636        2900 :         int result = 0;
     637        2900 :         bool null_column = false;
     638        2900 :         unsigned char *src = NULL;
     639             : 
     640        2900 :         CS_INT      srctype = 0;
     641        2900 :         CS_INT      srclen  = 0;
     642        2900 :         CS_INT      destlen  = 0;
     643        2900 :         CS_SMALLINT *nullind = NULL;
     644        2900 :         CS_INT      *datalen = NULL;
     645        2900 :         CS_BLKDESC *blkdesc = (CS_BLKDESC *) bulk;
     646        2900 :         CS_CONTEXT *ctx = CONN(blkdesc)->ctx;
     647             : 
     648        2900 :         tdsdump_log(TDS_DBG_FUNC, "_blk_get_col_data(%p, %p, %d)\n", bulk, bindcol, offset);
     649             : 
     650             :         /*
     651             :          * Retrieve the initial bound column_varaddress
     652             :          * and increment it if offset specified
     653             :          */
     654             : 
     655        2900 :         src = (unsigned char *) bindcol->column_varaddr;
     656        2900 :         if (!src) {
     657           0 :                 tdsdump_log(TDS_DBG_ERROR, "error source field not addressable\n");
     658             :                 return TDS_FAIL;
     659             :         }
     660             : 
     661        2900 :         src += offset * bindcol->column_bindlen;
     662             :         
     663        2900 :         if (bindcol->column_nullbind) {
     664        2800 :                 nullind = bindcol->column_nullbind;
     665        2800 :                 nullind += offset;
     666             :         }
     667        2900 :         if (bindcol->column_lenbind) {
     668        2900 :                 datalen = bindcol->column_lenbind;
     669        2900 :                 datalen += offset;
     670             :         }
     671             : 
     672        2900 :         srctype = bindcol->column_bindtype;          /* passes to cs_convert */
     673             : 
     674        2900 :         tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data srctype = %d\n", srctype);
     675        2900 :         tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data datalen = %d\n", datalen ? *datalen : -1);
     676             : 
     677        2900 :         if (datalen) {
     678        2900 :                 if (*datalen == CS_UNUSED) {
     679           0 :                         switch (srctype) {
     680             :                         case CS_LONG_TYPE:          srclen = 8; break;
     681             :                         case CS_FLOAT_TYPE:         srclen = 8; break;
     682             :                         case CS_MONEY_TYPE:         srclen = 8; break;
     683             :                         case CS_DATETIME_TYPE:  srclen = 8; break;
     684           0 :                         case CS_INT_TYPE:           srclen = 4; break;
     685           0 :                         case CS_UINT_TYPE:          srclen = 4; break;
     686           0 :                         case CS_REAL_TYPE:          srclen = 4; break;
     687           0 :                         case CS_MONEY4_TYPE:    srclen = 4; break;
     688           0 :                         case CS_DATETIME4_TYPE: srclen = 4; break;
     689           0 :                         case CS_SMALLINT_TYPE:  srclen = 2; break;
     690           0 :                         case CS_USMALLINT_TYPE:  srclen = 2; break;
     691           0 :                         case CS_TINYINT_TYPE:   srclen = 1; break;
     692           0 :                         case CS_BIT_TYPE:   srclen = 1; break;
     693             :                         case CS_BIGINT_TYPE:        srclen = 8; break;
     694             :                         case CS_UBIGINT_TYPE:       srclen = 8; break;
     695           0 :                         case CS_UNIQUE_TYPE:        srclen = 16; break;
     696           0 :                         default:
     697           0 :                                 tdsdump_log(TDS_DBG_ERROR, "Not fixed length type (%d) and datalen not specified\n",
     698           0 :                                             bindcol->column_bindtype);
     699             :                                 return TDS_FAIL;
     700             :                         }
     701             : 
     702             :                 } else {
     703        2900 :                         srclen = *datalen;
     704             :                 }
     705             :         }
     706        2900 :         if (srclen == 0) {
     707        1300 :                 if (nullind && *nullind == -1)
     708             :                         null_column = true;
     709             :         }
     710             : 
     711             :         if (!null_column) {
     712             :                 CS_DATAFMT_COMMON srcfmt, destfmt;
     713             :                 CS_INT desttype;
     714        1600 :                 TDS_SERVER_TYPE tds_desttype = TDS_INVALID_TYPE;
     715             : 
     716        1600 :                 srcfmt.datatype = srctype;
     717        1600 :                 srcfmt.maxlength = srclen;
     718             : 
     719        1600 :                 desttype = _cs_convert_not_client(NULL, bindcol, NULL, NULL);
     720        1600 :                 if (desttype == CS_ILLEGAL_TYPE)
     721        1600 :                         desttype = _ct_get_client_type(bindcol, false);
     722             :                 else
     723           0 :                         tds_desttype = bindcol->column_type;
     724        1600 :                 if (desttype == CS_ILLEGAL_TYPE)
     725           0 :                         return TDS_FAIL;
     726             : 
     727        1600 :                 destfmt.datatype  = desttype;
     728        1600 :                 destfmt.maxlength = bindcol->on_server.column_size;
     729        1600 :                 destfmt.precision = bindcol->column_prec;
     730        1600 :                 destfmt.scale     = bindcol->column_scale;
     731        1600 :                 destfmt.format    = CS_FMT_UNUSED;
     732             : 
     733             :                 /* if convert return FAIL mark error but process other columns */
     734        1600 :                 result = _cs_convert(ctx, &srcfmt, (CS_VOID *) src,
     735        1600 :                                      &destfmt, (CS_VOID *) bindcol->bcp_column_data->data, &destlen, tds_desttype);
     736        1600 :                 if (result != 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        2900 :         bindcol->bcp_column_data->datalen = destlen;
     744        2900 :         bindcol->bcp_column_data->is_null = null_column;
     745             : 
     746        2900 :         return TDS_SUCCESS;
     747             : }

Generated by: LCOV version 1.13