📄 blk.c
字号:
} if (is_numeric_type(bcpcol->on_server.column_type)) { tds_put_byte(tds, bcpcol->column_prec); tds_put_byte(tds, bcpcol->column_scale); } if (IS_TDS8_PLUS(tds) && is_collate_type(bcpcol->on_server.column_type)) { tds_put_n(tds, bcpcol->column_collation, 5); } if (is_blob_type(bcpcol->on_server.column_type)) { tds_put_smallint(tds, strlen(blkdesc->tablename)); tds_put_string(tds, blkdesc->tablename, strlen(blkdesc->tablename)); } /* FIXME support multibyte string */ tds_put_byte(tds, bcpcol->column_namelen); tds_put_string(tds, bcpcol->column_name, bcpcol->column_namelen); } return CS_SUCCEED;}static CS_RETCODE_blk_build_bcp_record(CS_BLKDESC *blkdesc, CS_INT offset){ TDSSOCKET *tds = blkdesc->con->tds_socket; TDSCOLUMN *bindcol; static const unsigned char CHARBIN_NULL[] = { 0xff, 0xff }; static const unsigned char GEN_NULL = 0x00; static const unsigned char textptr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static const unsigned char timestamp[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static const TDS_TINYINT textptr_size = 16; const unsigned char row_token = 0xd1; unsigned char *record; TDS_INT old_record_size; TDS_INT new_record_size; TDS_INT varint_4; TDS_SMALLINT varint_2; TDS_TINYINT varint_1; int row_pos; int row_sz_pos; TDS_SMALLINT row_size; int blob_cols = 0; int var_cols_written = 0; int i; tdsdump_log(TDS_DBG_FUNC, "_blk_build_bcp_record(offset %d)\n", offset); record = blkdesc->bindinfo->current_row; old_record_size = blkdesc->bindinfo->row_size; new_record_size = 0; if (IS_TDS7_PLUS(tds)) { for (i = 0; i < blkdesc->bindinfo->num_cols; i++) { bindcol = blkdesc->bindinfo->columns[i]; /* * dont send the (meta)data for timestamp columns, or * identity columns (unless indentity_insert is enabled */ if ((!blkdesc->identity_insert_on && bindcol->column_identity) || bindcol->column_timestamp) { continue; } if ((_blk_get_col_data(blkdesc, bindcol, offset)) != CS_SUCCEED) { tdsdump_log(TDS_DBG_INFO1, "blk_get_colData (column %d) failed\n", i + 1); return CS_FAIL; } tdsdump_log(TDS_DBG_INFO1, "gotten column %d length %d null %d\n", i + 1, bindcol->bcp_column_data->datalen, bindcol->bcp_column_data->is_null); if (bindcol->bcp_column_data->is_null) { if (bindcol->column_nullable) { switch (bindcol->on_server.column_type) { case XSYBCHAR: case XSYBVARCHAR: case XSYBBINARY: case XSYBVARBINARY: case XSYBNCHAR: case XSYBNVARCHAR: memcpy(record, CHARBIN_NULL, 2); record +=2; new_record_size +=2; break; default: *record = GEN_NULL; record++; new_record_size ++; break; } } else { /* No value or default value available and NULL not allowed. col = %d row = %d. */ _ctclient_msg(blkdesc->con, "blk_rowxfer", 2, 7, 1, 142, "%d, %d", i + 1, offset + 1); return CS_FAIL; } } else { switch (bindcol->column_varint_size) { case 4: if (is_blob_type(bindcol->on_server.column_type)) { *record = textptr_size; record++; memcpy(record, textptr, 16); record += 16; memcpy(record, timestamp, 8); record += 8; new_record_size += 25; } varint_4 = bindcol->bcp_column_data->datalen;#if WORDS_BIGENDIAN tds_swap_datatype(SYBINT4, (unsigned char *)&varint_4);#endif memcpy(record, &varint_4, 4); record += 4; new_record_size +=4; break; case 2: varint_2 = bindcol->bcp_column_data->datalen;#if WORDS_BIGENDIAN tds_swap_datatype(SYBINT2, (unsigned char *)&varint_2);#endif memcpy(record, &varint_2, 2); record += 2; new_record_size +=2; break; case 1: varint_1 = bindcol->bcp_column_data->datalen; if (is_numeric_type(bindcol->on_server.column_type)) varint_1 = tds_numeric_bytes_per_prec[bindcol->column_prec]; else varint_1 = bindcol->bcp_column_data->datalen; *record = varint_1; record++; new_record_size++; break; case 0: break; }#if WORDS_BIGENDIAN tds_swap_datatype(bindcol->on_server.column_type, bindcol->bcp_column_data->data);#endif if (is_numeric_type(bindcol->on_server.column_type)) { CS_NUMERIC *num = (CS_NUMERIC *) bindcol->bcp_column_data->data; if (IS_TDS7_PLUS(tds)) tds_swap_numeric((TDS_NUMERIC *) num); memcpy(record, num->array, tds_numeric_bytes_per_prec[num->precision]); record += tds_numeric_bytes_per_prec[num->precision]; new_record_size += tds_numeric_bytes_per_prec[num->precision]; } else { memcpy(record, bindcol->bcp_column_data->data, bindcol->bcp_column_data->datalen); record += bindcol->bcp_column_data->datalen; new_record_size += bindcol->bcp_column_data->datalen; } } tdsdump_log(TDS_DBG_INFO1, "old_record_size = %d new size = %d \n", old_record_size, new_record_size); } tds_put_byte(tds, row_token); /* 0xd1 */ tds_put_n(tds, blkdesc->bindinfo->current_row, new_record_size); } /* IS_TDS7_PLUS */ else { memset(record, '\0', old_record_size); /* zero the rowbuffer */ /* * offset 0 = number of var columns * offset 1 = row number. zeroed (datasever assigns) */ row_pos = 2; if ((row_pos = _blk_add_fixed_columns(blkdesc, offset, record, row_pos)) == CS_FAIL) return CS_FAIL; row_sz_pos = row_pos; /* potential variable columns to write */ if (blkdesc->var_cols) { if ((row_pos = _blk_add_variable_columns(blkdesc, offset, record, row_pos, &var_cols_written)) == CS_FAIL) return CS_FAIL; } row_size = row_pos; if (var_cols_written) { memcpy(&record[row_sz_pos], &row_size, sizeof(row_size)); record[0] = var_cols_written; } tdsdump_log(TDS_DBG_INFO1, "old_record_size = %d new size = %d \n", old_record_size, row_size); tds_put_smallint(tds, row_size); tds_put_n(tds, record, row_size); /* row is done, now handle any text/image data */ blob_cols = 0; for (i = 0; i < blkdesc->bindinfo->num_cols; i++) { bindcol = blkdesc->bindinfo->columns[i]; if (is_blob_type(bindcol->column_type)) { if ((_blk_get_col_data(blkdesc, bindcol, offset)) != CS_SUCCEED) { return CS_FAIL; } /* unknown but zero */ tds_put_smallint(tds, 0); tds_put_byte(tds, bindcol->column_type); tds_put_byte(tds, 0xff - blob_cols); /* * offset of txptr we stashed during variable * column processing */ tds_put_smallint(tds, bindcol->column_textpos); tds_put_int(tds, bindcol->bcp_column_data->datalen); tds_put_n(tds, bindcol->bcp_column_data->data, bindcol->bcp_column_data->datalen); blob_cols++; } } } return CS_SUCCEED;}static CS_RETCODE_blk_add_fixed_columns(CS_BLKDESC * blkdesc, int offset, unsigned char * rowbuffer, int start){ TDS_NUMERIC *num; int row_pos = start; TDSCOLUMN *bcpcol; int cpbytes; int i, j; tdsdump_log(TDS_DBG_FUNC, "_blk_add_fixed_columns (offset %d)\n", offset); for (i = 0; i < blkdesc->bindinfo->num_cols; i++) { bcpcol = blkdesc->bindinfo->columns[i]; if (!is_nullable_type(bcpcol->column_type) && !(bcpcol->column_nullable)) { tdsdump_log(TDS_DBG_FUNC, "_blk_add_fixed_columns column %d is a fixed column\n", i + 1); if (( _blk_get_col_data(blkdesc, bcpcol, offset)) != CS_SUCCEED) { return CS_FAIL; } if (bcpcol->bcp_column_data->is_null) { /* No value or default value available and NULL not allowed. col = %d row = %d. */ _ctclient_msg(blkdesc->con, "blk_rowxfer", 2, 7, 1, 142, "%d, %d", i + 1, offset + 1); return CS_FAIL; } if (is_numeric_type(bcpcol->column_type)) { num = (TDS_NUMERIC *) bcpcol->bcp_column_data->data; cpbytes = tds_numeric_bytes_per_prec[num->precision]; memcpy(&rowbuffer[row_pos], num->array, cpbytes); } else { cpbytes = bcpcol->bcp_column_data->datalen > bcpcol->column_size ? bcpcol->column_size : bcpcol->bcp_column_data->datalen; memcpy(&rowbuffer[row_pos], bcpcol->bcp_column_data->data, cpbytes); /* CHAR data may need padding out to the database length with blanks */ if (bcpcol->column_type == SYBCHAR && cpbytes < bcpcol->column_size) { for (j = cpbytes; j < bcpcol->column_size; j++) rowbuffer[row_pos + j] = ' '; } } row_pos += bcpcol->column_size; } } return row_pos;}/** * Add variable size columns to the row */static int_blk_add_variable_columns(CS_BLKDESC * blkdesc, int offset, unsigned char * rowbuffer, int start, int *var_cols){ TDSCOLUMN *bcpcol; TDS_NUMERIC *num; int row_pos; int cpbytes; unsigned char offset_table[256]; unsigned char adjust_table[256]; int offset_pos = 0; int adjust_pos = 0; int num_cols = 0; int last_adjustment_increment = 0; int this_adjustment_increment = 0; int i, adjust_table_entries_required; /* * Skip over two bytes. These will be used to hold the entire record length * once the record has been completely built. */ row_pos = start + 2; /* for each column in the target table */ tdsdump_log(TDS_DBG_FUNC, "_blk_add_variable_columns (offset %d)\n", offset); for (i = 0; i < blkdesc->bindinfo->num_cols; i++) { bcpcol = blkdesc->bindinfo->columns[i]; /* * is this column of "variable" type, i.e. NULLable * or naturally variable length e.g. VARCHAR */ if (is_nullable_type(bcpcol->column_type) || bcpcol->column_nullable) { tdsdump_log(TDS_DBG_FUNC, "_blk_add_variable_columns column %d is a variable column\n", i + 1); if ((_blk_get_col_data(blkdesc, bcpcol, offset)) != CS_SUCCEED) { return CS_FAIL; } /* * but if its a NOT NULL column, and we have no data * throw an error */ if (!(bcpcol->column_nullable) && bcpcol->bcp_column_data->is_null) { /* No value or default value available and NULL not allowed. col = %d row = %d. */ _ctclient_msg(blkdesc->con, "blk_rowxfer", 2, 7, 1, 142, "%d, %d", i + 1, offset + 1); return CS_FAIL; } if (is_blob_type(bcpcol->column_type)) { cpbytes = 16; bcpcol->column_textpos = row_pos; /* save for data write */ } else if (is_numeric_type(bcpcol->column_type)) { num = (TDS_NUMERIC *) bcpcol->bcp_column_data->data; cpbytes = tds_numeric_bytes_per_prec[num->precision]; memcpy(&rowbuffer[row_pos], num->array, cpbytes); } else { /* compute the length to copy to the row ** buffer */ if (bcpcol->bcp_column_data->is_null) { cpbytes = 0; } else { cpbytes = bcpcol->bcp_column_data->datalen > bcpcol->column_size ? bcpcol->column_size : bcpcol->bcp_column_data->datalen; memcpy(&rowbuffer[row_pos], bcpcol->bcp_column_data->data, cpbytes); } } /* if we have written data to the record for this column */ if (cpbytes > 0) { /* * update offset table. Each entry in the offset table is a single byte * so can only hold a maximum value of 255. If the real offset is more * than 255 we will have to add one or more entries in the adjust table */ offset_table[offset_pos++] = row_pos % 256; /* increment count of variable columns added to the record */ num_cols++; /* * how many times does 256 have to be added to the one byte offset to * calculate the REAL offset... */ this_adjustment_increment = row_pos / 256; /* has this changed since we did the last column... */ if (this_adjustment_increment > last_adjustment_increment) { /* * add n entries to the adjust table. each entry represents * an adjustment of 256 bytes, and each entry holds the * column number for which the adjustment needs to be made */ for ( adjust_table_entries_required = this_adjustment_increment - last_adjustment_increment; adjust_table_entries_required > 0; adjust_table_entries_required-- ) { adjust_table[adjust_pos++] = num_cols; } last_adjustment_increment = this_adjustment_increment; } row_pos += cpbytes; } } } if (num_cols) { /* * If we have written any variable columns to the record, add entries * to the offset and adjust tables for the end of data offset (as above). */ offset_table[offset_pos++] = row_pos % 256; /* * Write the offset data etc. to the end of the record, starting with * a count of variable columns (plus 1 for the eod offset) */ rowbuffer[row_pos++] = num_cols + 1; /* write the adjust table (right to left) */ for (i = adjust_pos - 1; i >= 0; i--) { rowbuffer[row_pos++] = adjust_table[i]; } /* write the offset table (right to left) */ for (i = offset_pos - 1; i >= 0; i--) { rowbuffer[row_pos++] = offset_table[i]; } } *var_cols = num_cols; if (num_cols == 0) /* we haven't written anything */ return start; else return row_pos;}static CS_RETCODE_blk_get_col_data(CS_BLKDESC *blkdesc, TDSCOLUMN *bindcol, int offset) { int result = 0; CS_INT null_column = 0; unsigned char *src = NULL; CS_INT srctype = 0; CS_INT srclen = 0; CS_INT destlen = 0; CS_SMALLINT *nullind = NULL; CS_INT *datalen = NULL; CS_CONTEXT *ctx = blkdesc->con->ctx; CS_DATAFMT srcfmt, destfmt; /* * retrieve the initial bound column_varaddress * and increment it if offset specified */ src = (unsigned char *) bindcol->column_varaddr; 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; } if (src) { srctype = bindcol->column_bindtype; /* used to pass to cs_convert */ tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data srctype = %d \n", srctype); tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data datalen = %d \n", *datalen); if (*datalen) { if (*datalen == CS_UNUSED) { switch (srctype) { case CS_LONG_TYPE: srclen = 8; break; case CS_FLOAT_TYPE: srclen = 8; break; case CS_MONEY_TYPE: srclen = 8; break; case CS_DATETIME_TYPE: srclen = 8; break; case CS_INT_TYPE: srclen = 4; break; case CS_REAL_TYPE: srclen = 4; break; case CS_MONEY4_TYPE: srclen = 4; break; case CS_DATETIME4_TYPE: srclen = 4; break; case CS_SMALLINT_TYPE: srclen = 2; break; case CS_TINYINT_TYPE: srclen = 1; break; default: printf("error not fixed length type (%d) and datalen not specified\n", bindcol->column_bindtype); return CS_FAIL; } } else { srclen = *datalen; } } if (srclen == 0) { if (*nullind == -1) { null_column = 1; } } if (!null_column) { srcfmt.datatype = srctype; srcfmt.maxlength = srclen; destfmt.datatype = _ct_get_client_type(bindcol->column_type, bindcol->column_usertype, bindcol->column_size); destfmt.maxlength = bindcol->column_size; destfmt.precision = bindcol->column_prec; destfmt.scale = bindcol->column_scale; destfmt.format = CS_FMT_UNUSED; /* if convert return FAIL mark error but process other columns */ if ((result = cs_convert(ctx, &srcfmt, (CS_VOID *) src, &destfmt, (CS_VOID *) bindcol->bcp_column_data->data, &destlen)) != CS_SUCCEED) { tdsdump_log(TDS_DBG_INFO1, "convert failed for %d \n", srcfmt.datatype); return CS_FAIL; } } bindcol->bcp_column_data->datalen = destlen; bindcol->bcp_column_data->is_null = null_column; return CS_SUCCEED; } else { printf("error source field not addressable \n"); return CS_FAIL; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -