bcp_init rturns访问冲突

时间:2015-10-05 12:28:10

标签: c++ sql-server odbc

我正在尝试使用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);

我得到一个例外,说访问违规。我没有收到任何错误,只是一个例外。 有谁知道我该如何解决这个问题?

1 个答案:

答案 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.0sqlncli11.lib合作。

选项(1)和(4)正在运行。

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

希望这有帮助。