bcp.c
来自「在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动」· C语言 代码 · 共 2,086 行 · 第 1/5 页
C
2,086 行
if (hostcol->tab_colnum < 1 || hostcol->tab_colnum > resinfo->num_cols) continue; curcol = resinfo->columns[hostcol->tab_colnum - 1]; if (hostcol->datatype == 0) hostcol->datatype = curcol->column_type; /* work out how much space to allocate for output data */ /* TODO use a function for fixed types */ switch (hostcol->datatype) { case SYBINT1: buflen = destlen = 1; break; case SYBINT2: buflen = destlen = 2; break; case SYBINT4: buflen = destlen = 4; break; case SYBINT8: buflen = destlen = 8; break; case SYBREAL: buflen = destlen = 4; break; case SYBFLT8: buflen = destlen = 8; break; case SYBDATETIME: buflen = destlen = 8; break; case SYBDATETIME4: buflen = destlen = 4; break; case SYBBIT: buflen = destlen = 1; break; case SYBBITN: buflen = destlen = 1; break; case SYBMONEY: buflen = destlen = 8; break; case SYBMONEY4: buflen = destlen = 4; break; case SYBCHAR: case SYBVARCHAR: switch (curcol->column_type) { case SYBVARCHAR: buflen = curcol->column_size + 1; destlen = -1; break; case SYBCHAR: buflen = curcol->column_size + 1; if (curcol->column_nullable) destlen = -1; else destlen = -2; break; case SYBTEXT: /* FIXME column_size ?? if 2gb ?? */ buflen = curcol->column_size + 1; destlen = -2; break; case SYBINT1: buflen = 4 + 1; /* 255 */ destlen = -1; break; case SYBINT2: buflen = 6 + 1; /* -32768 */ destlen = -1; break; case SYBINT4: buflen = 11 + 1; /* -2147483648 */ destlen = -1; break; case SYBINT8: buflen = 20 + 1; /* -9223372036854775808 */ destlen = -1; break; case SYBNUMERIC: case SYBDECIMAL: buflen = 40 + 1; /* 10 to the 38 */ destlen = -1; break; case SYBFLT8: buflen = 40 + 1; /* 10 to the 38 */ destlen = -1; break; case SYBDATETIME: case SYBDATETIME4: buflen = 255 + 1; destlen = -1; break; default: buflen = 255 + 1; destlen = -1; break; } break; default: buflen = destlen = 255; } hostcol->bcp_column_data = tds_alloc_bcp_column_data(buflen); hostcol->bcp_column_data->datalen = destlen; } /* fetch a row of data from the server */ /* * TODO above we allocate many buffer just to convert and store * to file.. avoid all that passages... */ while (tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE) == TDS_SUCCEED) { if (result_type != TDS_ROW_RESULT && result_type != TDS_COMPUTE_RESULT) break; row_of_query++; /* skip rows outside of the firstrow/lastrow range , if specified */ if (dbproc->hostfileinfo->firstrow <= row_of_query && row_of_query <= MAX(dbproc->hostfileinfo->lastrow, 0x7FFFFFFF)) { /* Go through the hostfile columns, finding those that relate to database columns. */ for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) { size_t written = 0; hostcol = dbproc->hostfileinfo->host_columns[i]; if (hostcol->tab_colnum < 1 || hostcol->tab_colnum > resinfo->num_cols) { continue; } curcol = resinfo->columns[hostcol->tab_colnum - 1]; src = curcol->column_data; if (is_blob_type(curcol->column_type)) { src = (BYTE *) ((TDSBLOB *) src)->textvalue; } srctype = tds_get_conversion_type(curcol->column_type, curcol->column_size); if (curcol->column_cur_size < 0) { srclen = 0; hostcol->bcp_column_data->is_null = 1; } else { if (is_numeric_type(curcol->column_type)) srclen = sizeof(TDS_NUMERIC); else srclen = curcol->column_cur_size; hostcol->bcp_column_data->is_null = 0; } if (hostcol->bcp_column_data->is_null) { buflen = 0; } else { /* * if we are converting datetime to string, need to override any * date time formats already established */ if ((srctype == SYBDATETIME || srctype == SYBDATETIME4) && (hostcol->datatype == SYBCHAR || hostcol->datatype == SYBVARCHAR)) { tds_datecrack(srctype, src, &when); buflen = tds_strftime((TDS_CHAR *)hostcol->bcp_column_data->data, 256, bcpdatefmt, &when); } else { /* * For null columns, the above work to determine the output buffer size is moot, * because bcpcol->data_size is zero, so dbconvert() won't write anything, * and returns zero. */ /* TODO check for text !!! */ buflen = dbconvert(dbproc, srctype, src, srclen, hostcol->datatype, hostcol->bcp_column_data->data, hostcol->bcp_column_data->datalen); /* * Special case: When outputting database varchar data * (either varchar or nullable char) dbconvert may have * trimmed trailing blanks such that nothing is left. * In this case we need to put a single blank to the output file. */ if (( curcol->column_type == SYBVARCHAR || (curcol->column_type == SYBCHAR && curcol->column_nullable) ) && srclen > 0 && buflen == 0) { strcpy ((char *)hostcol->bcp_column_data->data, " "); buflen = 1; } } } /* The prefix */ if ((plen = hostcol->prefix_len) == -1) { if (is_blob_type(hostcol->datatype)) plen = 4; else if (!(is_fixed_type(hostcol->datatype))) plen = 2; else if (curcol->column_nullable) plen = 1; else plen = 0; /* cache */ hostcol->prefix_len = plen; } switch (plen) { case 0: break; case 1: ti = buflen; written = fwrite(&ti, sizeof(ti), 1, hostfile); break; case 2: si = buflen; written = fwrite(&si, sizeof(si), 1, hostfile); break; case 4: li = buflen; written = fwrite(&li, sizeof(li), 1, hostfile); break; } if( plen != 0 && written != 1 ) { dbperror(dbproc, SYBEBCWE, errno); return FAIL; } /* The data */ if (hostcol->column_len != -1) { buflen = buflen > hostcol->column_len ? hostcol->column_len : buflen; } if (buflen > 0) { written = fwrite(hostcol->bcp_column_data->data, buflen, 1, hostfile); if (written < 1) { dbperror(dbproc, SYBEBCWE, errno); return FAIL; } } /* The terminator */ if (hostcol->terminator && hostcol->term_len > 0) { written = fwrite(hostcol->terminator, hostcol->term_len, 1, hostfile); if (written < 1) { dbperror(dbproc, SYBEBCWE, errno); return FAIL; } } } rows_written++; } } if (fclose(hostfile) != 0) { dbperror(dbproc, SYBEBCUC, errno); return (FAIL); } if (dbproc->hostfileinfo->firstrow > 0 && row_of_query < dbproc->hostfileinfo->firstrow) { /* * The table which bulk-copy is attempting to * copy to a host-file is shorter than the * number of rows which bulk-copy was instructed to skip. */ /* TODO reset TDSSOCKET state */ dbperror(dbproc, SYBETTS, 0); return (FAIL); } *rows_copied = rows_written; return SUCCEED;}static RETCODE_bcp_check_eof(DBPROCESS * dbproc, FILE *file, int icol){ int errnum = errno; tdsdump_log(TDS_DBG_FUNC, "_bcp_check_eof(%p, %p, %d)\n", dbproc, file, icol); assert(dbproc); assert(file); if (feof(file)) { if (icol == 0) { tdsdump_log(TDS_DBG_FUNC, "Normal end-of-file reached while loading bcp data file.\n"); return (NO_MORE_ROWS); } dbperror(dbproc, SYBEBEOF, errnum); return (FAIL); } dbperror(dbproc, SYBEBCRE, errnum); return (FAIL);}/** * \ingroup dblib_bcp_internal * \brief * * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param hostfile * \param row_error * * \return MORE_ROWS, NO_MORE_ROWS, 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 RETCODE_bcp_read_hostfile(DBPROCESS * dbproc, FILE * hostfile, int *row_error){ TDSCOLUMN *bcpcol = NULL; BCP_HOSTCOLINFO *hostcol; TDS_TINYINT ti; TDS_SMALLINT si; TDS_INT li; TDS_INT desttype; TDS_CHAR *coldata; int i, collen, data_is_null; tdsdump_log(TDS_DBG_FUNC, "_bcp_read_hostfile(%p, %p, %p)\n", dbproc, hostfile, row_error); assert(dbproc); assert(hostfile); assert(row_error); /* for each host file column defined by calls to bcp_colfmt */ for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) { tdsdump_log(TDS_DBG_FUNC, "parsing host column %d\n", i + 1); hostcol = dbproc->hostfileinfo->host_columns[i]; data_is_null = 0; collen = 0; hostcol->column_error = 0; /* * If this host file column contains table data, * find the right element in the table/column list. * FIXME I think tab_colnum can be out of range - freddy77 */ if (hostcol->tab_colnum) { bcpcol = dbproc->bcpinfo->bindinfo->columns[hostcol->tab_colnum - 1]; } /* detect prefix len */ if (bcpcol && hostcol->prefix_len == -1) { int plen = bcpcol->column_varint_size; hostcol->prefix_len = plen == 5 ? 4 : plen; } /* a prefix length, if extant, specifies how many bytes to read */ if (hostcol->prefix_len > 0) { switch (hostcol->prefix_len) { case 1: if (fread(&ti, 1, 1, hostfile) != 1) return _bcp_check_eof(dbproc, hostfile, i); collen = ti ? ti : -1; break; case 2: if (fread(&si, 2, 1, hostfile) != 1) return _bcp_check_eof(dbproc, hostfile, i); collen = si; break; case 4: if (fread(&li, 4, 1, hostfile) != 1) return _bcp_check_eof(dbproc, hostfile, i); collen = li; break; default: /* FIXME return error, remember that prefix_len can be 3 */ assert(hostcol->prefix_len <= 4); break; } /* TODO test all NULL types */ /* TODO for < -1 error */ if (collen <= -1) { data_is_null = 1; collen = 0; } } /* if (Max) column length specified take that into consideration. (Meaning what, exactly?) */ if (!data_is_null && hostcol->column_len >= 0) { if (hostcol->column_len == 0) data_is_null = 1; else { if (collen) collen = (hostcol->column_len < collen) ? hostcol->column_len : collen; else collen = hostcol->column_len; } } tdsdump_log(TDS_DBG_FUNC, "prefix_len = %d collen = %d \n", hostcol->prefix_len, collen); /* Fixed Length data - this overrides anything else specified */ if (is_fixed_type(hostcol->datatype)) { collen = tds_get_size_by_type(hostcol->datatype); } /* * The data file either contains prefixes stating the length, or is delimited. * If delimited, we "measure" the field by looking for the terminator, then read it, * and set collen to the field's post-iconv size. */ if (hostcol->term_len > 0) { /* delimited data file */ int file_bytes_left, file_len; size_t col_bytes_left; offset_type len; iconv_t cd; len = _bcp_measure_terminated_field(hostfile, hostcol->terminator, hostcol->term_len);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?