Skip to content
1 change: 1 addition & 0 deletions include/bkpublic.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ CS_RETCODE blk_rowxfer(CS_BLKDESC * blkdesc);
CS_RETCODE blk_rowxfer_mult(CS_BLKDESC * blkdesc, CS_INT * row_count);
CS_RETCODE blk_sendrow(CS_BLKDESC * blkdesc, CS_BLK_ROW * row);
CS_RETCODE blk_sendtext(CS_BLKDESC * blkdesc, CS_BLK_ROW * row, CS_BYTE * buffer, CS_INT buflen);
CS_RETCODE blk_sethints(CS_BLKDESC* blkdesc, CS_CHAR* hints, CS_INT hintslen);
CS_RETCODE blk_srvinit(SRV_PROC * srvproc, CS_BLKDESC * blkdescp);
CS_RETCODE blk_textxfer(CS_BLKDESC * blkdesc, CS_BYTE * buffer, CS_INT buflen, CS_INT * outlen);

Expand Down
13 changes: 10 additions & 3 deletions include/ctlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,11 @@ typedef union
CS_DATAFMT user;
} CS_DATAFMT_INTERNAL;

/* Alternate _cs_convert return values, which double as message numbers */
#define BLK_CONV_OVERFLOW 25
#define BLK_CONV_SYNTAX_ERROR 26
#define BLK_CONV_TRUNCATION 42

/*
* internal prototypes
*/
Expand All @@ -396,9 +401,11 @@ int _cs_locale_copy_inplace(CS_LOCALE *new_locale, CS_LOCALE *orig);
CS_INT _ct_get_string_length(const char *buf, CS_INT buflen);

int _cs_convert_not_client(CS_CONTEXT *ctx, const TDSCOLUMN *curcol, CONV_RESULT *convert_buffer, unsigned char **p_src);

CS_RETCODE _cs_convert(CS_CONTEXT * ctx, const CS_DATAFMT_COMMON * srcfmt, CS_VOID * srcdata,
const CS_DATAFMT_COMMON * destfmt, CS_VOID * destdata, CS_INT * resultlen, TDS_SERVER_TYPE desttype);
/* NB: only _blk_get_col_data is expected to pass a non-NULL handle */
CS_RETCODE _cs_convert(CS_CONTEXT * ctx, const CS_DATAFMT_COMMON * srcfmt,
CS_VOID * srcdata, const CS_DATAFMT_COMMON * destfmt,
CS_VOID * destdata, CS_INT * resultlen,
TDS_SERVER_TYPE desttype, CS_VOID ** handle);
bool _ct_is_large_identifiers_version(CS_INT version);
const CS_DATAFMT_COMMON * _ct_datafmt_common(CS_CONTEXT * ctx, const CS_DATAFMT * datafmt);
const CS_DATAFMT_LARGE *_ct_datafmt_conv_in(CS_CONTEXT * ctx, const CS_DATAFMT * datafmt, CS_DATAFMT_LARGE * fmtbuf);
Expand Down
9 changes: 9 additions & 0 deletions include/freetds/tds.h
Original file line number Diff line number Diff line change
Expand Up @@ -1676,6 +1676,10 @@ typedef struct tds5_colinfo
TDS_TINYINT status;
TDS_SMALLINT offset;
TDS_INT length;
TDS_TINYINT dflt;

TDS_INT dflt_size;
TDS_UCHAR* dflt_value;
} TDS5COLINFO;

struct tds_bcpinfo
Expand All @@ -1691,6 +1695,11 @@ struct tds_bcpinfo
TDSRESULTINFO *bindinfo;
TDS5COLINFO *sybase_colinfo;
TDS_INT sybase_count;
TDS_INT text_sent;
TDS_INT next_col;
TDS_INT blob_cols;
TDS_INT rows_sent;
bool with_triggers;
};

TDSRET tds_bcp_init(TDSSOCKET *tds, TDSBCPINFO *bcpinfo);
Expand Down
168 changes: 143 additions & 25 deletions src/ctlib/blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ static void _blk_null_error(TDSBCPINFO *bcpinfo, int index, int offset);
static TDSRET _blk_get_col_data(TDSBCPINFO *bulk, TDSCOLUMN *bcpcol, int offset);
static CS_RETCODE _blk_rowxfer_in(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred);
static CS_RETCODE _blk_rowxfer_out(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred);
static void _blk_clean_desc(CS_BLKDESC * blkdesc);

#define CONN(bulk) ((CS_CONNECTION *) (bulk)->bcpinfo.parent)

Expand Down Expand Up @@ -282,19 +283,47 @@ blk_done(CS_BLKDESC * blkdesc, CS_INT type, CS_INT * outrow)
*outrow = rows_copied;

/* free allocated storage in blkdesc & initialise flags, etc. */
tds_deinit_bcpinfo(&blkdesc->bcpinfo);

blkdesc->bcpinfo.direction = 0;
blkdesc->bcpinfo.bind_count = CS_UNUSED;
blkdesc->bcpinfo.xfer_init = false;

_blk_clean_desc(blkdesc);
break;

case CS_BLK_CANCEL:
/* discard staged query data */
tds->out_pos = sizeof(TDS_HEADER);
/* can't transition directly from SENDING to PENDING */
tds_set_state(tds, TDS_WRITING);
tds_set_state(tds, TDS_PENDING);

tds_send_cancel(tds);

if (TDS_FAILED(tds_process_cancel(tds))) {
_ctclient_msg(NULL, CONN(blkdesc), "blk_done",
2, 5, 1, 140, "");
return CS_FAIL;
}

if (outrow)
*outrow = 0;

/* free allocated storage in blkdesc & initialise flags, etc. */
_blk_clean_desc(blkdesc);
break;
}

return CS_SUCCEED;
}

static void _blk_clean_desc (CS_BLKDESC * blkdesc)
{
tds_deinit_bcpinfo(&blkdesc->bcpinfo);

blkdesc->bcpinfo.direction = 0;
blkdesc->bcpinfo.bind_count = CS_UNUSED;
blkdesc->bcpinfo.xfer_init = false;
blkdesc->bcpinfo.text_sent = 0;
blkdesc->bcpinfo.next_col = 0;
blkdesc->bcpinfo.blob_cols = 0;
}

CS_RETCODE
blk_drop(CS_BLKDESC * blkdesc)
{
Expand Down Expand Up @@ -485,6 +514,17 @@ blk_sendtext(CS_BLKDESC * blkdesc, CS_BLK_ROW * row, CS_BYTE * buffer, CS_INT bu
return CS_FAIL;
}

CS_RETCODE
blk_sethints(CS_BLKDESC* blkdesc, CS_CHAR* hints, CS_INT hintslen)
{
if (blkdesc != NULL
&& tds_dstr_copyn(&blkdesc->bcpinfo.hint, hints, hintslen) != NULL)
return CS_SUCCEED;
else
return CS_FAIL;

}

CS_RETCODE
blk_srvinit(SRV_PROC * srvproc, CS_BLKDESC * blkdescp)
{
Expand All @@ -497,10 +537,39 @@ blk_srvinit(SRV_PROC * srvproc, CS_BLKDESC * blkdescp)
CS_RETCODE
blk_textxfer(CS_BLKDESC * blkdesc, CS_BYTE * buffer, CS_INT buflen, CS_INT * outlen)
{
TDSSOCKET *tds;
TDSCOLUMN *bindcol;

tdsdump_log(TDS_DBG_FUNC, "blk_textxfer(%p, %p, %d, %p)\n", blkdesc, buffer, buflen, outlen);

tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_textxfer()\n");
return CS_FAIL;
if (blkdesc == NULL || buffer == NULL
|| blkdesc->bcpinfo.direction != CS_BLK_IN) {
return CS_FAIL;
}

tds = CONN(blkdesc)->tds_socket;

bindcol = blkdesc->bcpinfo.bindinfo->columns
[blkdesc->bcpinfo.next_col-1];

if (bindcol->column_varaddr != NULL) {
return CS_FAIL;
}

bindcol->column_cur_size = buflen;
bindcol->column_lenbind = &bindcol->column_cur_size;
bindcol->column_varaddr = (TDS_CHAR*) buffer;

if (TDS_FAILED(tds_bcp_send_record(tds, &blkdesc->bcpinfo,
_blk_get_col_data, _blk_null_error,
0))) {
return CS_FAIL;
} else if (blkdesc->bcpinfo.next_col == 0) {
return CS_END_DATA; /* all done */
} else {
bindcol->column_varaddr = NULL;
return CS_SUCCEED; /* still need more data */
}
}

static CS_RETCODE
Expand Down Expand Up @@ -597,23 +666,28 @@ _blk_rowxfer_in(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred

if (!blkdesc->bcpinfo.xfer_init) {

blkdesc->bcpinfo.xfer_init = true;

/*
* first call the start_copy function, which will
* retrieve details of the database table columns
*/

if (TDS_FAILED(tds_bcp_start_copy_in(tds, &blkdesc->bcpinfo))) {
_ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");

blkdesc->bcpinfo.xfer_init = false;
return CS_FAIL;
}

blkdesc->bcpinfo.xfer_init = true;
}

for (each_row = 0; each_row < rows_to_xfer; each_row++ ) {

if (tds_bcp_send_record(tds, &blkdesc->bcpinfo, _blk_get_col_data, _blk_null_error, each_row) == TDS_SUCCESS) {
/* FIXME */
if (blkdesc->bcpinfo.next_col > 0)
return CS_BLK_HAS_TEXT;
} else {
return CS_FAIL;
}
}

Expand Down Expand Up @@ -644,31 +718,46 @@ _blk_get_col_data(TDSBCPINFO *bulk, TDSCOLUMN *bindcol, int offset)
CS_INT *datalen = NULL;
CS_BLKDESC *blkdesc = (CS_BLKDESC *) bulk;
CS_CONTEXT *ctx = CONN(blkdesc)->ctx;
BCPCOLDATA *coldata = bindcol->bcp_column_data;

tdsdump_log(TDS_DBG_FUNC, "_blk_get_col_data(%p, %p, %d)\n", bulk, bindcol, offset);

if (bindcol->column_nullbind) {
nullind = bindcol->column_nullbind;
nullind += offset;
}
if (bindcol->column_lenbind) {
datalen = bindcol->column_lenbind;
datalen += offset;
}

/*
* Retrieve the initial bound column_varaddress
* and increment it if offset specified
*/

src = (unsigned char *) bindcol->column_varaddr;
if (!src) {
if (nullind && *nullind == -1) {
null_column = true;
}

bindcol->bcp_column_data->datalen = *datalen;
bindcol->bcp_column_data->is_null = null_column;

if (null_column) {
return TDS_SUCCESS;
} else if (is_blob_col(bindcol)
&& bindcol->column_varaddr == NULL) {
/* Data will come piecemeal, via blk_textxfer. */
return TDS_NO_MORE_RESULTS;
}

tdsdump_log(TDS_DBG_ERROR, "error source field not addressable\n");
return TDS_FAIL;
}

src += offset * bindcol->column_bindlen;

if (bindcol->column_nullbind) {
nullind = bindcol->column_nullbind;
nullind += offset;
}
if (bindcol->column_lenbind) {
datalen = bindcol->column_lenbind;
datalen += offset;
}

srctype = bindcol->column_bindtype; /* passes to cs_convert */

tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data srctype = %d\n", srctype);
Expand Down Expand Up @@ -708,10 +797,11 @@ _blk_get_col_data(TDSBCPINFO *bulk, TDSCOLUMN *bindcol, int offset)
null_column = true;
}

if (!null_column) {
if (!null_column && !is_blob_type(bindcol->column_type)) {
CS_DATAFMT_COMMON srcfmt, destfmt;
CS_INT desttype;
TDS_SERVER_TYPE tds_desttype = TDS_INVALID_TYPE;
TDSSOCKET * tds = CONN(blkdesc)->tds_socket;

srcfmt.datatype = srctype;
srcfmt.maxlength = srclen;
Expand All @@ -731,13 +821,41 @@ _blk_get_col_data(TDSBCPINFO *bulk, TDSCOLUMN *bindcol, int offset)
destfmt.format = CS_FMT_UNUSED;

/* if convert return FAIL mark error but process other columns */
result = _cs_convert(ctx, &srcfmt, (CS_VOID *) src,
&destfmt, (CS_VOID *) bindcol->bcp_column_data->data, &destlen, tds_desttype);
if (result != CS_SUCCEED) {
result = _cs_convert(ctx, &srcfmt, (CS_VOID *) src, &destfmt,
(CS_VOID *) coldata->data, &destlen,
tds_desttype,
(CS_VOID **) &coldata->data);
if (result > CS_SUCCEED) {
const TDSRESULTINFO * info = bulk->bindinfo;
TDS_USMALLINT colnum;
for (colnum = 0; colnum < info->num_cols; ++colnum) {
if (info->columns[colnum] == bindcol)
break;
}
_ctclient_msg(ctx, CONN(blkdesc), "blk_rowxfer",
2, 7, 1, result, "%d,%hu",
bulk->rows_sent + 1, colnum + 1);
}
if (result != CS_SUCCEED && result != BLK_CONV_TRUNCATION) {
tdsdump_log(TDS_DBG_ERROR, "conversion from srctype %d to desttype %d failed\n",
srctype, desttype);
return TDS_FAIL;
}
if (destfmt.maxlength != bindcol->column_size
&& destfmt.datatype == CS_CHAR_TYPE
&& is_fixed_type(_ct_get_server_type(tds, srctype))) {
size_t out_len;
TDS_UCHAR *buf
= (TDS_UCHAR *) tds_convert_string
(tds, bindcol->char_conv,
(char *) coldata->data, destlen,
&out_len);
if (buf != NULL && buf != coldata->data) {
free(coldata->data);
coldata->data = buf;
destlen = (CS_INT) out_len;
}
}
}

bindcol->bcp_column_data->datalen = destlen;
Expand Down
Loading