bcp.c
来自「在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动」· C语言 代码 · 共 2,086 行 · 第 1/5 页
C
2,086 行
if (len > 0x7fffffffl || len < 0) { *row_error = TRUE; tdsdump_log(TDS_DBG_FUNC, "_bcp_measure_terminated_field returned -1!\n"); dbperror(dbproc, SYBEBCOR, 0); return (FAIL); } collen = len; if (collen == 0) data_is_null = 1; tdsdump_log(TDS_DBG_FUNC, "_bcp_measure_terminated_field returned %d\n", collen); /* * Allocate a column buffer guaranteed to be big enough hold the post-iconv data. */ file_len = collen; if (bcpcol->char_conv) { if (bcpcol->on_server.column_size > bcpcol->column_size) collen = (collen * bcpcol->on_server.column_size) / bcpcol->column_size; cd = bcpcol->char_conv->to_wire; tdsdump_log(TDS_DBG_FUNC, "Adjusted collen is %d.\n", collen); } else { cd = (iconv_t) - 1; } coldata = calloc(1, 1 + collen); if (coldata == NULL) { *row_error = TRUE; tdsdump_log(TDS_DBG_FUNC, "calloc returned NULL pointer!\n"); dbperror(dbproc, SYBEMEM, errno); return (FAIL); } /* * Read and convert the data */ col_bytes_left = collen; /* TODO make tds_iconv_fread handle terminator directly to avoid fseek in _bcp_measure_terminated_field */ file_bytes_left = tds_iconv_fread(cd, hostfile, file_len, hostcol->term_len, coldata, &col_bytes_left); collen -= col_bytes_left; /* tdsdump_log(TDS_DBG_FUNC, "collen is %d after tds_iconv_fread()\n", collen); */ if (file_bytes_left != 0) { tdsdump_log(TDS_DBG_FUNC, "col %d: %d of %d bytes unread\nfile_bytes_left != 0!\n", (i+1), file_bytes_left, collen); *row_error = TRUE; free(coldata); dbperror(dbproc, SYBEBCOR, 0); return FAIL; } /* * TODO: * Dates are a problem. In theory, we should be able to read non-English dates, which * would contain non-ASCII characters. One might suppose we should convert date * strings to ISO-8859-1 (or another canonical form) here, because tds_convert() can't be * expected to deal with encodings. But instead date strings are read verbatim and * passed to tds_convert() without even waving to iconv(). For English dates, this works, * because English dates expressed as UTF-8 strings are indistinguishable from the ASCII. */ } else { /* unterminated field */#if 0 bcpcol = dbproc->bcpinfo->bindinfo->columns[hostcol->tab_colnum - 1]; if (collen == 0 || bcpcol->column_nullable) { if (collen != 0) { /* A fixed length type */ TDS_TINYINT len; if (fread(&len, sizeof(len), 1, hostfile) != 1) { if (i != 0) dbperror(dbproc, SYBEBCRE, errno); return (FAIL); } if (len < 0) dbperror(dbproc, SYBEBCNL, errno); /* TODO 255 for NULL ?? check it, perhaps 0 */ collen = len == 255 ? -1 : len; } else { TDS_SMALLINT len; if (fread(&len, sizeof(len), 1, hostfile) != 1) { if (i != 0) dbperror(dbproc, SYBEBCRE, errno); return (FAIL); } if (len < 0) dbperror(dbproc, SYBEBCNL, errno); collen = len; } /* TODO if collen < -1 error */ if (collen <= -1) { collen = 0; data_is_null = 1; } tdsdump_log(TDS_DBG_FUNC, "Length read from hostfile: collen is now %d, data_is_null is %d\n", collen, data_is_null); }#endif coldata = (TDS_CHAR *) calloc(1, 1 + collen); if (coldata == NULL) { *row_error = TRUE; dbperror(dbproc, SYBEMEM, errno); return (FAIL); } if (collen) { /* * Read and convert the data * TODO: Call tds_iconv_fread() instead of fread(3). * The columns should each have their iconv cd set, and noncharacter data * should have -1 as the iconv cd, causing tds_iconv_fread() to not attempt * any conversion. We do not need a datatype switch here to decide what to do. * As of 0.62, this *should* actually work. All that remains is to change the * call and test it. */ tdsdump_log(TDS_DBG_FUNC, "Reading %d bytes from hostfile.\n", collen); if (fread(coldata, collen, 1, hostfile) != 1) { free(coldata); return _bcp_check_eof(dbproc, hostfile, i); } } } /* * If we read no bytes and we're at end of file AND this is the first column, * then we've stumbled across the finish line. Tell the caller we failed to read * anything but encountered no error. */ if (i == 0 && collen == 0 && feof(hostfile)) { free(coldata); tdsdump_log(TDS_DBG_FUNC, "Normal end-of-file reached while loading bcp data file.\n"); return NO_MORE_ROWS; } /* * At this point, however the field was read, however big it was, its address is coldata and its size is collen. */ tdsdump_log(TDS_DBG_FUNC, "Data read from hostfile: collen is now %d, data_is_null is %d\n", collen, data_is_null); if (hostcol->tab_colnum) { if (data_is_null) { bcpcol->bcp_column_data->is_null = 1; bcpcol->bcp_column_data->datalen = 0; } else { bcpcol->bcp_column_data->is_null = 0; desttype = tds_get_conversion_type(bcpcol->column_type, bcpcol->column_size); /* special hack for text columns */ if (bcpcol->column_size == 4096 && collen > bcpcol->column_size) { /* "4096" might not matter */ BYTE *oldbuffer = bcpcol->bcp_column_data->data; switch (desttype) { case SYBTEXT: case SYBNTEXT: case SYBIMAGE: case SYBVARBINARY: case XSYBVARBINARY: case SYBLONGBINARY: /* Reallocate enough space for the data from the file. */ bcpcol->column_size = 8 + collen; /* room to breathe */ bcpcol->bcp_column_data->data = (BYTE *) realloc(bcpcol->bcp_column_data->data, bcpcol->column_size); if (!bcpcol->bcp_column_data->data) { dbperror(dbproc, SYBEMEM, errno); free(oldbuffer); free(coldata); return FAIL; } break; default: break; } } /* end special hack for text columns */ /* * FIXME bcpcol->bcp_column_data->data && bcpcol->column_size ?? * It seems a buffer overflow waiting... */ bcpcol->bcp_column_data->datalen = dbconvert(dbproc, hostcol->datatype, (const BYTE *) coldata, collen, desttype, bcpcol->bcp_column_data->data, bcpcol->column_size); if (bcpcol->bcp_column_data->datalen == -1) { hostcol->column_error = HOST_COL_CONV_ERROR; *row_error = 1; /* FIXME possible integer overflow if off_t is 64bit and long int 32bit */ tdsdump_log(TDS_DBG_FUNC, "_bcp_read_hostfile failed to convert %d bytes at offset 0x%lx in the data file.\n", collen, (unsigned long int) ftello(hostfile) - collen); } /* trim trailing blanks from character data */ if (desttype == SYBCHAR || desttype == SYBVARCHAR) { bcpcol->bcp_column_data->datalen = rtrim((char *) bcpcol->bcp_column_data->data, bcpcol->bcp_column_data->datalen); } } if (!hostcol->column_error) { if (bcpcol->bcp_column_data->datalen <= 0) { /* Are we trying to insert a NULL ? */ if (!bcpcol->column_nullable) { /* too bad if the column is not nullable */ hostcol->column_error = HOST_COL_NULL_ERROR; *row_error = 1; dbperror(dbproc, SYBEBCNN, 0); } } } } free(coldata); } return MORE_ROWS;}/* * Look for the next terminator in a host data file, and return the data size. * \return size of field, excluding the terminator. * \remarks The current offset will be unchanged. If an error was encountered, the returned size will be -1. * The caller should check for that possibility, but the appropriate message should already have been emitted. * The caller can then use tds_iconv_fread() to read-and-convert the file's data * into host format, or, if we're not dealing with a character column, just fread(3). *//** * \ingroup dblib_bcp_internal * \brief * * \param hostfile * \param terminator * \param term_len * * \return SUCCEED or FAIL. * \sa BCP_SETL(), bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), bcp_done(), bcp_exec(), bcp_getl(), bcp_init(), bcp_moretext(), bcp_options(), bcp_readfmt(), bcp_sendrow() */static offset_type_bcp_measure_terminated_field(FILE * hostfile, BYTE * terminator, int term_len){ char *sample; int errnum; int sample_size, bytes_read = 0; offset_type size; const offset_type initial_offset = ftello(hostfile); tdsdump_log(TDS_DBG_FUNC, "_bcp_measure_terminated_field(%p, %p, %d)\n", hostfile, terminator, term_len); if ((sample = malloc(term_len)) == NULL) { dbperror(NULL, SYBEMEM, errno); return -1; } for (sample_size = 1; (bytes_read = fread(sample, sample_size, 1, hostfile)) != 0;) { bytes_read *= sample_size; /* * Check for terminator. */ /* * TODO use memchr for performance, * optimize this strange loop - freddy77 */ if (*sample == *terminator) { if (sample_size == term_len) { /* * If we read a whole terminator, compare the whole sequence and, if found, go home. */ if (memcmp(sample, terminator, term_len) == 0) { free(sample); size = ftello(hostfile) - initial_offset; if (size < 0 || 0 != fseeko(hostfile, initial_offset, SEEK_SET)) { /* FIXME emit message */ return -1; } return size - term_len; } /* * If we tried to read a terminator and found something else, then we read a * terminator's worth of data. Back up N-1 bytes, and revert to byte-at-a-time testing. */ if (sample_size > 1) { sample_size--; if (0 != fseeko(hostfile, -sample_size, SEEK_CUR)) { /* FIXME emit message */ return -1; } } sample_size = 1; continue; } else { /* * Found start of terminator, but haven't read a full terminator's length yet. * Back up, read a whole terminator, and try again. */ assert(bytes_read == 1); ungetc(*sample, hostfile); sample_size = term_len; continue; } assert(0); /* should not arrive here */ } } free(sample); /* * To get here, we ran out of memory, or encountered an error (or EOF) with the file. * EOF is a surprise, because if we read a complete field with its terminator, * we would have returned without attempting to read past end of file. */ if (feof(hostfile)) { errnum = errno; if (initial_offset == ftello(hostfile)) { return 0; } else { /* a cheat: we don't have dbproc, so pass zero */ dbperror(0, SYBEBEOF, errnum); } } else if (ferror(hostfile)) { dbperror(0, SYBEBCRE, errno); } return -1;}/** * Add fixed size columns to the row *//** * \ingroup dblib_bcp_internal * \brief * * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param behaviour * \param rowbuffer * \param start * * \return SUCCEED or FAIL. * \sa BCP_SETL(), bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_colfmt_ps(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_control(), bcp_done(), bcp_exec(), bcp_getl(), bcp_init(), bcp_moretext(), bcp_options(), bcp_readfmt(), bcp_sendrow() */static int_bcp_add_fixed_columns(DBPROCESS * dbproc, BEHAVIOUR behaviour, BYTE * rowbuffer, int start){ TDS_NUMERIC *num; int row_pos = start; TDSCOLUMN *bcpcol; int cpbytes; int i, j; assert(dbproc); assert(rowbuffer); tdsdump_log(TDS_DBG_FUNC, "_bcp_add_fixed_columns(%p, %d, %p, %d)\n", dbproc, behaviour, rowbuffer, start); for (i = 0; i < dbproc->bcpinfo->bindinfo->num_cols; i++) { bcpcol = dbproc->bcpinfo->bindinfo->columns[i]; if (!is_nullable_type(bcpcol->column_type) && !(bcpcol->column_nullable)) { tdsdump_log(TDS_DBG_FUNC, "_bcp_add_fixed_columns column %d is a fixed column\n", i + 1); if (behaviour == BCP_REC_FETCH_DATA) { if ((_bcp_get_col_data(dbproc, bcpcol)) != SUCCEED) { tdsdump_log(TDS_DBG_INFO1, "bcp_get_colData (column %d) failed\n", i + 1); return FAIL; } } if (bcpcol->bcp_column_data->is_null) { dbperror(dbproc, SYBEBCNN, 0); return 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 *//** * \ingroup dblib_bcp_internal * \brief * * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param behaviour Whether the data are already in the TDSCOLUMN or should by copied from the buffer bound by bcp_bind(). * \param rowbuffer The row image that will be sent to the server. * \param start Where to begin copying data into the rowbuffer. * \param pncols Address of output variable holding the count of columns added to the rowbuffer. * * \return length of (potentially modified) rowbuffer, or FAIL. * \sa _bcp_send_bcp_record(), _bcp_get_col_data */static int_bcp_add_variable_columns(DBPROCESS * dbproc, BEHAVIOUR behaviour, BYTE * rowbuffer, int start, int *pncols){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?