我正在尝试使用c ++中的odbc在sql server中进行批量复制。 这是我的代码:
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>
#include<tchar.h>
SQLHENV henv = SQL_NULL_HENV;
HDBC hdbc1 = SQL_NULL_HDBC, hdbc2 = SQL_NULL_HDBC;
SQLHSTMT hstmt2 = SQL_NULL_HSTMT;
void Cleanup() {
if (hstmt2 != SQL_NULL_HSTMT)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt2);
if (hdbc1 != SQL_NULL_HDBC) {
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
}
if (hdbc2 != SQL_NULL_HDBC) {
SQLDisconnect(hdbc2);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc2);
}
if (henv != SQL_NULL_HENV)
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
void HandleDiagnosticRecord (SQLHANDLE hHandle,
SQLSMALLINT hType,
RETCODE RetCode)
{
SQLSMALLINT iRec = 0;
SQLINTEGER iError;
WCHAR wszMessage[1000];
WCHAR wszState[SQL_SQLSTATE_SIZE+1];
if (RetCode == SQL_INVALID_HANDLE)
{
fwprintf(stderr, L"Invalid handle!\n");
return;
}
while (SQLGetDiagRec(hType,
hHandle,
++iRec,
wszState,
&iError,
wszMessage,
(SQLSMALLINT)(sizeof(wszMessage) / sizeof(WCHAR)),
(SQLSMALLINT *)NULL) == SQL_SUCCESS)
{
// Hide data truncated..
if (wcsncmp(wszState, L"01004", 5))
{
fwprintf(stderr, L"[%5.5s] %s (%d)\n", wszState, wszMessage, iError);
}
}
}
#define TRYODBC(h, ht, x) { RETCODE rc = x;\
if (rc != SQL_SUCCESS) \
{ \
HandleDiagnosticRecord (h, ht, rc); \
} \
if (rc == SQL_ERROR) \
{ \
fwprintf(stderr, L"Error in " L#x L"\n"); \
Sleep(30000); \
} \
}
void extract_error(
char *fn,
SQLHANDLE handle,
SQLSMALLINT type)
{
SQLINTEGER i = 0;
SQLINTEGER native;
SQLWCHAR state[ 7 ];
SQLWCHAR text[256];
SQLSMALLINT len;
SQLRETURN ret;
fprintf(stderr,
"\n"
"The driver reported the following diagnostics whilst running "
"%s\n\n",
fn);
do
{
ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
sizeof(text), &len );
if (SQL_SUCCEEDED(ret))
printf("%s:%ld:%ld:%s\n", state, i, native, text);
}
while( ret == SQL_SUCCESS );
}
int main() {
RETCODE retcode;
// BCP variables.
char *terminator = "\0";
// bcp_done takes a different format return code because it returns number of rows bulk copied
// after the last bcp_batch call.
DBINT cRowsDone = 0;
// Set up separate return code for bcp_sendrow so it is not using the same retcode as SQLFetch.
RETCODE SendRet;
// Allocate the ODBC environment and save handle.
retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLAllocHandle(Env) Failed\n\n");
Cleanup();
return(9);
}
// Notify ODBC that this is an ODBC 3.0 app.
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLSetEnvAttr(ODBC version) Failed\n\n");
Cleanup();
return(9);
}
// Allocate ODBC connection handle, set bulk copy mode, and connect.
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLAllocHandle(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
retcode = SQLSetConnectAttr(hdbc1, SQL_COPT_SS_BCP, (void *)SQL_BCP_ON, SQL_IS_INTEGER);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLSetConnectAttr(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
// sample uses Integrated Security, create the SQL Server DSN using Windows NT authentication
SQLWCHAR dsn[30] = L"mssqltest"; //Name DNS
SQLWCHAR user[10] = L"di_test";
SQLWCHAR pass[10] = L"di_test";
SQLWCHAR tb[20]=L"information1";
retcode = SQLConnectW(hdbc1, (SQLWCHAR *)dsn, SQL_NTS, (SQLWCHAR *) user, SQL_NTS, (SQLWCHAR *) pass, SQL_NTS);
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
printf("SQLConnect() Failed\n\n");
Cleanup();
return(9);
}
// TRYODBC(hdbc1, SQL_HANDLE_DBC, retcode);
// Initialize the bulk copy.
retcode = bcp_init(hdbc1,L"information1", NULL, NULL, DB_IN);
if ( (retcode != SUCCEED) ) {
printf("bcp_init(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
//Define our array
SQLINTEGER custIDs[] = { 1, 2, 3, 4};
// Bind the program variables for the bulk copy.
retcode = bcp_bind(hdbc1, (BYTE *)custIDs[0], 4, SQL_VARLEN_DATA, NULL, (INT)NULL, SQLINT4, 2);
if ( (retcode != SUCCEED) ) {
printf("bcp_bind(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
// Could normally use strlen to calculate the bcp_bind cbTerm parameter, but this terminator
// is a null byte (\0), which gives strlen a value of 0. Explicitly give cbTerm a value of 1.
retcode = bcp_bind(hdbc1, (BYTE *)custIDs[0], 4, SQL_VARLEN_DATA, NULL, (INT)NULL, SQLINT4, 3);
if ( (retcode != SUCCEED) ) {
printf("bcp_bind(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
if ( (SendRet = bcp_sendrow(hdbc1) ) != SUCCEED ) {
printf("bcp_sendrow(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
cRowsDone = bcp_done(hdbc1);
if ( (cRowsDone == -1) ) {
printf("bcp_done(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
printf("Number of rows bulk copied after last bcp_batch call = %d.\n", cRowsDone);
// Cleanup.
SQLFreeHandle(SQL_HANDLE_STMT, hstmt2);
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
SQLDisconnect(hdbc2);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc2);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
在该行:
retcode = bcp_init(hdbc1,L"information1", NULL, NULL, DB_IN);
我得到一个例外,说访问违规。我没有收到任何错误,只是一个例外。 有谁知道我该如何解决这个问题?
答案 0 :(得分:2)
我在一个win32计划中使用bcp_xxxx
功能已经12到15年了。该程序是在VS6上编译的,目前仍在生产中。
我最近在VS2015上重写了这个项目(最后......)。而且我也遇到了像你这样bcp_xxxx
函数的问题。
最初的VS6程序包含以下文件:
#include <sql.h>
#include <sqlext.h>
#include "C:\Program Files\Microsoft SQL Server\80\Tools\DevTools\Include\odbcss.h"
SQLDriverConnect()
函数与包含Driver=SQL Server
的连接字符串一起使用。
odbcbcp.lib
已添加到链接库列表中。没有问题。
该程序已完全重新访问VS2015,将适当的ODBC函数更改为其版本3.x,并允许32或64位二进制文件具有UNICODE或ANSI字符集。
最近的文档建议在使用sqlncli.h
函数时使用sqlncli11.lib
标题和bcp_xxxx
:
#include <sql.h>
#include <sqlext.h>
#define _SQLNCLI_ODBC_
#ifdef _WIN64
#include "C:\Program Files\Microsoft SQL Server\110\SDK\Include\sqlncli.h"
#else
#include "C:\Program Files (x86)\Microsoft SQL Server\110\SDK\Include\sqlncli.h"
#endif
我按照建议做了,然后......崩溃
然后我链接回odbcbcp.lib
,它就像一个魅力。
所以,我开始搜索如何使用sqlncli11.lib
,我发现ODBC连接字符串应该包含Driver=SQL Server Native Client 11.0
。
简而言之:
- (1)Driver=SQL Server
odbcbcp.lib
的作品
- (2)Driver=SQL Server
sqlncli11.lib
使bcp_init()
崩溃
- (3)Driver=SQL Server Native Client 11.0
odbcbcp.lib
使bcp_init()
失败(返回FAIL
= 0)
- (4)Driver=SQL Server Native Client 11.0
与sqlncli11.lib
合作。
选项(1)和(4)正在运行。
但我发现使用选项(4)可以让查询运行得更快! 所以我会保留最后一个。
希望这有帮助。