bcp.c

来自「在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动」· C语言 代码 · 共 2,086 行 · 第 1/5 页

C
2,086
字号
 */RETCODEbcp_colfmt(DBPROCESS * dbproc, int host_colnum, int host_type, int host_prefixlen, DBINT host_collen, const BYTE * host_term,	   int host_termlen, int table_colnum){	BCP_HOSTCOLINFO *hostcol;	tdsdump_log(TDS_DBG_FUNC, "bcp_colfmt(%p, %d, %d, %d, %d, %p)\n", 		    dbproc, host_colnum, host_type, host_prefixlen, (int) host_collen, host_term);	CHECK_DBPROC();	DBPERROR_RETURN(IS_TDSDEAD(dbproc->tds_socket), SYBEDDNE);	CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);	CHECK_PARAMETER(dbproc->hostfileinfo, SYBEBIVI, FAIL);	/* Microsoft specifies a "file_termlen" of zero if there's no terminator */	if (dbproc->msdblib && host_termlen == 0)		host_termlen = -1;	if (dbproc->hostfileinfo->host_colcount == 0) {		dbperror(dbproc, SYBEBCBC, 0);		return FAIL;	}	if (host_colnum < 1) {		dbperror(dbproc, SYBEBCFO, 0);		return FAIL;	}	if (host_prefixlen != 0 && host_prefixlen != 1 && host_prefixlen != 2 && host_prefixlen != 4 && host_prefixlen != -1) {		dbperror(dbproc, SYBEBCPREF, 0);		return FAIL;	}	if (table_colnum <= 0 && host_type == 0) {		dbperror(dbproc, SYBEBCPCTYP, 0);		return FAIL;	}	if (host_prefixlen == 0 && host_collen == -1 && host_termlen == -1 && !is_fixed_type(host_type)) {		dbperror(dbproc, SYBEVDPT, 0);		return FAIL;	}	if (host_collen < -1) {		dbperror(dbproc, SYBEBCHLEN, 0);		return FAIL;	}	/* No official error message.  Fix and warn. */	if (is_fixed_type(host_type) && (host_collen != -1 && host_collen != 0)) {		tdsdump_log(TDS_DBG_FUNC,			    "bcp_colfmt: changing host_collen to -1 from %d for fixed type %d.\n", 			    host_collen, host_type);		host_collen = -1;	}	/* 	 * If there's a positive terminator length, we need a valid terminator pointer.	 * If the terminator length is 0 or -1, then there's no terminator.	 */	if (host_term == NULL && host_termlen > 0 || host_term != NULL && host_termlen == 0) {		dbperror(dbproc, SYBEVDPT, 0);	/* "all variable-length data must have either a length-prefix ..." */		return FAIL;	}	hostcol = dbproc->hostfileinfo->host_columns[host_colnum - 1];	/* TODO add precision scale and join with bcp_colfmt_ps */	hostcol->host_column = host_colnum;	hostcol->datatype = host_type;	hostcol->prefix_len = host_prefixlen;	hostcol->column_len = host_collen;	if (host_term && host_termlen >= 0) {		free(hostcol->terminator);		if ((hostcol->terminator = malloc(host_termlen)) == NULL) {			dbperror(dbproc, SYBEMEM, errno);			return FAIL;		}		memcpy(hostcol->terminator, host_term, host_termlen);	}	hostcol->term_len = host_termlen;	hostcol->tab_colnum = table_colnum;	return SUCCEED;}/**  * \ingroup dblib_bcp * \brief Specify the format of a host file for bulk copy purposes,  * 	with precision and scale support for numeric and decimal columns. *  * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param host_colnum datafile column number (starting with 1, not zero). * \param host_type dataype token describing the data type in \a host_colnum.  E.g. SYBCHAR for character data. * \param host_prefixlen size of the prefix in the datafile column, if any.  For delimited files: zero.   *			May be 0, 1, 2, or 4 bytes.  The prefix will be read as an integer (not a character string) from the  * 			data file, and will be interpreted the data size of that column, in bytes.   * \param host_collen maximum size of datafile column, exclusive of any prefix/terminator.  Just the data, ma'am.   *		Special values: *			- \b 0 indicates NULL.   *			- \b -1 for fixed-length non-null datatypes *			- \b -1 for variable-length datatypes (e.g. SYBCHAR) where the length is established  *				by a prefix/terminator.   * \param host_term the sequence of characters that will serve as a column terminator (delimiter) in the datafile.   * 			Often a tab character, but can be any string of any length.  Zero indicates no terminator.   * 			Special characters: *				- \b '\\0' terminator is an ASCII NUL. *				- \b '\\t' terminator is an ASCII TAB. *				- \b '\\n' terminator is an ASCII NL. * \param host_termlen the length of \a host_term, in bytes.  * \param table_colnum Nth column, starting at 1, in the table that maps to \a host_colnum.   * 	If there is a column in the datafile that does not map to a table column, set \a table_colnum to zero.   * \param typeinfo something * \todo Not implemented. * \return SUCCEED or FAIL. * \sa 	bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(), *	bcp_control(), bcp_done(), bcp_exec(), bcp_init(), bcp_sendrow */RETCODEbcp_colfmt_ps(DBPROCESS * dbproc, int host_colnum, int host_type,	      int host_prefixlen, DBINT host_collen, BYTE * host_term, int host_termlen, int table_colnum, DBTYPEINFO * typeinfo){	tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED: bcp_colfmt_ps(%p, %d, %d)\n", dbproc, host_colnum, host_type);	CHECK_DBPROC();	DBPERROR_RETURN(IS_TDSDEAD(dbproc->tds_socket), SYBEDDNE);	CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);		/* dbperror(dbproc, , 0);	 Illegal precision specified */	/* TODO see bcp_colfmt */	return FAIL;}/**  * \ingroup dblib_bcp * \brief Set BCP options for uploading a datafile *  * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param field symbolic constant indicating the option to be set, one of: *  		- \b BCPMAXERRS Maximum errors tolerated before quitting. The default is 10. *  		- \b BCPFIRST The first row to read in the datafile. The default is 1.  *  		- \b BCPLAST The last row to read in the datafile. The default is to copy all rows. A value of *                  	-1 resets this field to its default? *  		- \b BCPBATCH The number of rows per batch.  Default is 0, meaning a single batch.  * \param value The value for \a field. * * \remarks These options control the behavior of bcp_exec().   * When writing to a table from application host memory variables,  * program logic controls error tolerance and batch size.  *  * \return SUCCEED or FAIL. * \sa 	bcp_batch(), bcp_bind(), bcp_colfmt(), bcp_collen(), bcp_colptr(), bcp_columns(), bcp_done(), bcp_exec(), bcp_options() */RETCODEbcp_control(DBPROCESS * dbproc, int field, DBINT value){	tdsdump_log(TDS_DBG_FUNC, "bcp_control(%p, %d, %d)\n", dbproc, field, value);	CHECK_DBPROC();	DBPERROR_RETURN(IS_TDSDEAD(dbproc->tds_socket), SYBEDDNE);	CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);	if (field == BCPKEEPIDENTITY) {		dbproc->bcpinfo->identity_insert_on = (value != 0);		return SUCCEED;	}	CHECK_PARAMETER(dbproc->hostfileinfo, SYBEBIVI, FAIL);	switch (field) {	case BCPMAXERRS:		dbproc->hostfileinfo->maxerrs = value;		break;	case BCPFIRST:		dbproc->hostfileinfo->firstrow = value;		break;	case BCPLAST:		dbproc->hostfileinfo->lastrow = value;		break;	case BCPBATCH:		dbproc->hostfileinfo->batch = value;		break;	default:		dbperror(dbproc, SYBEIFNB, 0);		return FAIL;	}	return SUCCEED;}/* * \ingroup dblib_bcp * \brief Get BCP batch option *  * \param dbproc contains all information needed by db-lib to manage communications with the server. * \remarks This function is specific to FreeTDS.   *  * \return the value that was set by bcp_control. * \sa 	bcp_batch(), bcp_control() */intbcp_getbatchsize(DBPROCESS * dbproc){	return dbproc->hostfileinfo->batch;}/**  * \ingroup dblib_bcp * \brief Set "hints" for uploading a file.  A FreeTDS-only function.   *  * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param option symbolic constant indicating the option to be set, one of: * 		- \b BCPLABELED Not implemented. * 		- \b BCPHINTS The hint to be passed when the bulk-copy begins.   * \param value The string constant for \a option a/k/a the hint.  One of: * 		- \b ORDER The data are ordered in accordance with the table's clustered index. * 		- \b ROWS_PER_BATCH The batch size * 		- \b KILOBYTES_PER_BATCH The approximate number of kilobytes to use for a batch size * 		- \b TABLOCK Lock the table * 		- \b CHECK_CONSTRAINTS Apply constraints * \param valuelen The strlen of \a value.   *  * \return SUCCEED or FAIL. * \sa 	bcp_control(),  * 	bcp_exec(),  * \todo Simplify.  Remove \a valuelen, and dbproc->bcpinfo->hint = strdup(hints[i]) */RETCODEbcp_options(DBPROCESS * dbproc, int option, BYTE * value, int valuelen){	int i;	static const char *const hints[] = {		"ORDER", "ROWS_PER_BATCH", "KILOBYTES_PER_BATCH", "TABLOCK", "CHECK_CONSTRAINTS", NULL	};	tdsdump_log(TDS_DBG_FUNC, "bcp_options(%p, %d, %p, %d)\n", dbproc, option, value, valuelen);	CHECK_DBPROC();	DBPERROR_RETURN(IS_TDSDEAD(dbproc->tds_socket), SYBEDDNE);	CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);	CHECK_NULP(value, "bcp_options", 3, FAIL);	switch (option) {	case BCPLABELED:		tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED bcp option: BCPLABELED\n");		break;	case BCPHINTS:		if (!value || valuelen <= 0)			break;		for (i = 0; hints[i]; i++) {	/* look up hint */			if (strncasecmp((char *) value, hints[i], strlen(hints[i])) == 0) {				dbproc->bcpinfo->hint = hints[i];	/* safe: hints[i] is static constant, above */				return SUCCEED;			}		}		tdsdump_log(TDS_DBG_FUNC, "failed, no such hint\n");		break;	default:		tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED bcp option: %u\n", option);		break;	}	return FAIL;}/**  * \ingroup dblib_bcp * \brief Override bcp_bind() by pointing to a different host variable. *  * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param colptr The pointer, the address of your variable.  * \param table_column The 1-based column ordinal in the table.   * \remarks Use between calls to bcp_sendrow().  After calling bcp_colptr(),  * 		subsequent calls to bcp_sendrow() will bind to the new address.   * \return SUCCEED or FAIL. * \sa 	bcp_bind(), bcp_collen(), bcp_sendrow()  */RETCODEbcp_colptr(DBPROCESS * dbproc, BYTE * colptr, int table_column){	TDSCOLUMN *curcol;	tdsdump_log(TDS_DBG_FUNC, "bcp_colptr(%p, %p, %d)\n", dbproc, colptr, table_column);	CHECK_DBPROC();	DBPERROR_RETURN(IS_TDSDEAD(dbproc->tds_socket), SYBEDDNE);	CHECK_PARAMETER(dbproc->bcpinfo, SYBEBCPI, FAIL);	CHECK_PARAMETER(dbproc->bcpinfo->bindinfo, SYBEBCPI, FAIL);	/* colptr can be NULL */	if (dbproc->bcpinfo->direction != DB_IN) {		dbperror(dbproc, SYBEBCPN, 0);		return FAIL;	}	if (table_column <= 0 || table_column > dbproc->bcpinfo->bindinfo->num_cols) {		dbperror(dbproc, SYBEBCPN, 0);		return FAIL;	}		curcol = dbproc->bcpinfo->bindinfo->columns[table_column - 1];	curcol->column_varaddr = (TDS_CHAR *)colptr;	return SUCCEED;}/**  * \ingroup dblib_bcp * \brief See if BCP_SETL() was used to set the LOGINREC for BCP work.   *  * \param login Address of the LOGINREC variable to be passed to dbopen().  *  * \return TRUE or FALSE. * \sa 	BCP_SETL(), bcp_init(), dblogin(), dbopen() */DBBOOLbcp_getl(LOGINREC * login){	TDSLOGIN *tdsl = login->tds_login;	tdsdump_log(TDS_DBG_FUNC, "bcp_getl(%p)\n", login);	return (tdsl->bulk_copy);}/**  * \ingroup dblib_bcp_internal * \brief  * *  * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param rows_copied  *  * \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 RETCODE_bcp_exec_out(DBPROCESS * dbproc, DBINT * rows_copied){	FILE *hostfile;	int i;	TDSSOCKET *tds;	TDSRESULTINFO *resinfo;	TDSCOLUMN *curcol = NULL;	BCP_HOSTCOLINFO *hostcol;	BYTE *src;	int srctype;	int srclen;	int buflen;	int destlen;	int plen;	TDS_INT result_type;	TDS_TINYINT ti;	TDS_SMALLINT si;	TDS_INT li;	TDSDATEREC when;	int row_of_query;	int rows_written;	char *bcpdatefmt;	int tdsret;	tdsdump_log(TDS_DBG_FUNC, "_bcp_exec_out(%p, %p)\n", dbproc, rows_copied);	assert(dbproc);	assert(rows_copied);	tds = dbproc->tds_socket;	assert(tds);	if (!(hostfile = fopen(dbproc->hostfileinfo->hostfile, "w"))) {		dbperror(dbproc, SYBEBCUO, errno);		return FAIL;	}	bcpdatefmt = getenv("FREEBCP_DATEFMT");	if (!bcpdatefmt)		bcpdatefmt = "%Y-%m-%d %H:%M:%S.%z";	if (dbproc->bcpinfo->direction == DB_QUERYOUT ) {		if (tds_submit_query(tds, dbproc->bcpinfo->tablename) == TDS_FAIL) {			return FAIL;		}	} else {		/* TODO quote if needed */		if (tds_submit_queryf(tds, "select * from %s", dbproc->bcpinfo->tablename) == TDS_FAIL) {			return FAIL;		}	}	tdsret = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS);	if (tdsret == TDS_FAIL || tdsret == TDS_CANCELLED) {		fclose(hostfile);		return FAIL;	}	if (!tds->res_info) {		/* TODO flush/cancel to keep consistent state */		fclose(hostfile);		return FAIL;	}	resinfo = tds->res_info;	row_of_query = 0;	rows_written = 0;	/*	 * Before we start retrieving the data, go through the defined	 * host file columns. If the host file column is related to a	 * table column, then allocate some space sufficient to hold	 * the resulting data (converted to whatever host file format)	 */	for (i = 0; i < dbproc->hostfileinfo->host_colcount; i++) {		hostcol = dbproc->hostfileinfo->host_columns[i];

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?