Bcp_init返回访问冲突

bcp_init rturns access violation

本文关键字:访问冲突 返回 init Bcp      更新时间:2023-10-16

我试图在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 "
            "%snn",
            fn);
    do
    {
      ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
      sizeof(text), &len );
      if (SQL_SUCCEEDED(ret))
      printf("%s:%ld:%ld:%sn", state, i, native, text);
    }
    while( ret == SQL_SUCCESS );
  }

int main() {
   RETCODE retcode;
   // BCP variables.
   char *terminator = "";
   // 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) Failednn");
      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) Failednn");
      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) Failednn");
      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) Failednn");
      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() Failednn");
      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) Failednn");
      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) Failednn");
      Cleanup();
      return(9);
   }
   // Could normally use strlen to calculate the bcp_bind cbTerm parameter, but this terminator 
   // is a null byte (), 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) Failednn");
      Cleanup();
      return(9);
   }

   if ( (SendRet = bcp_sendrow(hdbc1) ) != SUCCEED ) {
         printf("bcp_sendrow(hdbc1) Failednn");
         Cleanup();
         return(9);
      }
   cRowsDone = bcp_done(hdbc1);
   if ( (cRowsDone == -1) ) {
      printf("bcp_done(hdbc1) Failednn");
      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);
我得到一个异常,访问冲突。除了一个异常,我没有收到任何错误。有人知道我该怎么解决这个问题吗?

我已经在一个win32程序中使用bcp_xxxx函数12-15年了。该程序是在VS6上编译的,目前仍在生产中。

我最近在VS2015上重写了这个项目(终于…)。我和你一样,也有bcp_xxxx函数的问题。

最初的VS6程序包含以下文件:

#include <sql.h>  
#include <sqlext.h>  
#include "C:Program FilesMicrosoft SQL Server80ToolsDevToolsIncludeodbcss.h"  

SQLDriverConnect()函数使用包含Driver=SQL Server的连接字符串。

odbcbcp.lib被添加到链接器库列表中。没有问题。

该程序已在VS2015中完全重新访问,在适当的时候将ODBC函数更改为其版本3。允许使用UNICODE或ANSI字符集的32位或64位二进制文件。

最近的文档建议在使用bcp_xxxx函数时使用sqlncli.h头和sqlncli11.lib:

#include <sql.h>
#include <sqlext.h>
#define _SQLNCLI_ODBC_
#ifdef _WIN64
#include "C:Program FilesMicrosoft SQL Server110SDKIncludesqlncli.h"
#else
#include "C:Program Files (x86)Microsoft SQL Server110SDKIncludesqlncli.h"
#endif

我按照建议做了,然后…崩溃。
然后我链接回odbcbcp.lib,它就像一个魅力。

所以,我开始搜索如何使用sqlncli11.lib,我发现ODBC连接字符串应该包含Driver=SQL Server Native Client 11.0
简而言之:
- (1) Driver=SQL Serverodbcbcp.lib作品
- (2) Driver=SQL Serversqlncli11.lib使bcp_init()崩溃
- (3) Driver=SQL Server Native Client 11.0odbcbcp.lib使bcp_init()失败(它返回FAIL =0)
- (4) Driver=SQL Server Native Client 11.0sqlncli11.lib作品。

选项(1)和(4)正在工作。

但是我也发现使用option(4)可以让查询运行得更快!
所以我保留最后一个。