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 + -
显示快捷键?