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