Microsoft ODBC无法创建有效的句柄

时间:2018-09-25 21:11:09

标签: c++ sql-server odbc

我正在使用Microsoft的ODBC驱动程序将C ++ / Linux应用程序连接到远程运行的SQL Server数据库,并且当我尝试连接到数据库时,调用失败,显示为SQL_INVALID_HANDLE。通读他们的documentation,我发现:

  

SQL_INVALID_HANDLE函数由于无效的环境,连接,语句或描述符句柄而失败。这表示编程错误。 SQLGetDiagRec或SQLGetDiagField没有其他信息。仅当句柄是空指针或错误类型时(例如,为需要连接句柄的参数传递语句句柄时),才返回此代码。

足够公平,但是在connect语句之前的句柄和环境创建过程中,没有任何错误。另外,对于第二个参数,他们的文档说如果没有桌面窗口,我可以传递一个空指针(在此Linux控制台应用程序中就是这种情况)。这是根据微软的example program改编而成的MVCE:

#include "sql.h"
#include "sqlext.h"
#include "msodbcsql.h"
#include <iostream>
#include <string>

int main(int, char**)
{
  using std::cerr;
  using std::endl;
  SQLHENV henv;  
  SQLHDBC hdbc;
  HWND dhandle = nullptr; // no desktop handle in linux
  SQLHSTMT hstmt;  
  SQLRETURN retcode;  
  SQLCHAR OutConnStr[255];  
  SQLSMALLINT OutConnStrLen;

  retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);  
  if (!(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO))
    cerr << "SQLAllocHandle (environment) failed " << retcode << endl;

  retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);
  if (!(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO))
    cerr << "SQLSetEnvAttr failed " << retcode << endl;

  retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
  if (!(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO))
    cerr << "SQLAllocHandle (connection) failed " << retcode << endl;

  retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);  
  if (!(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO))
    cerr << "SQLSetConnectAttr failed " << retcode << endl;

  std::string dsn = "DRIVER={ODBC Driver 17 for SQL Server};SERVER=*.*.*,1433;DATABASE=***;UID=***;PWD=***";
  retcode = SQLDriverConnect(hdbc, dhandle, (SQLCHAR*)dsn.c_str(), dsn.length(), OutConnStr, 255, &OutConnStrLen, SQL_DRIVER_PROMPT);
  if (!(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO))
    cerr << "SQLDriverConnect failed " << retcode << endl;

  // cleanup code redacted for brevity

  return 0;
}

程序输出SQLDriverConnect failed -2,即SQL_INVALID_HANDLE。我很沮丧hdbc显然是正确的类型,并且在调试器中对其进行检查后发现它不是null。

可能值得注意的是,使用pyodbc在Python程序中可以使用完全相同的连接字符串。不过,似乎C ++程序甚至还远远没有看到该字符串。只是不喜欢我发送给connect调用的句柄。

Microsoft的文档明确指出他们没有提供其他信息。如果有人可以提供任何有关如何诊断/调试的指导,我将不胜感激。

此应用程序在Centos 7上使用gcc 4.9.1。

4 个答案:

答案 0 :(得分:0)

在Unix中,句柄不必为显示对话框而必须为非null值。

答案 1 :(得分:0)

经过两周的挖掘,结果发现这是某种版本控制问题。

最终,该程序将通过Microsoft在libmsodbcsql.so中的扩展名进行一些BCP上传。事实证明,该库还具有许多SQL*函数的实现,这些函数在该测试程序中失败。当我更改链接的顺序,使libodbc.so在MSFT扩展库之前,以便加载程序首先找到那些实现时,程序运行正常。

我很好奇为什么会这样,这可能表明我做错了其他事情,这可能会困扰我。但是至少到目前为止,我已经能够连接到数据库并进行基本的查询和更新。

感谢那些帮助过的人。

答案 2 :(得分:0)

对于SQL Server中的任何句柄,必须在使用前分配它!

所以顺序是环境,连接和声明。

示例:

SQLHENV hEnv = nullptr;
SQLHDBC hDbc = nullptr;
SQLHSTMT hStmt = NULL;

分配

SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv);
SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc);
SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt);

下面是示例代码,可以为您提供帮助。

基本快速

在sql server数据库中创建表并插入一些数据

create table test (id int, name nvarchar(128));

插入一些数据

insert into test (id,name) values (1, 'Awesome Name');

用于查询表中项目的C ++代码

#include <iostream>
#include <string>
#include <sql.h>
#include <sqlext.h>


int main(int argc, char **argv) {
    SQLHENV hEnv = nullptr;
    SQLHDBC hDbc = nullptr;
    SQLHSTMT hStmt = NULL;

    /**
     * Allocate environment handle
     */
    SQLRETURN allocReturn = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv);

    //Set environment
    SQLRETURN setEnvReturn = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

    //Allocate connection handle

    SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc);
    SQLCHAR *connection_string = (SQLCHAR *)
            "DRIVER={ODBC Driver 17 for SQL Server};SERVER=localhost,1433;DATABASE=database;UID=sa;PWD=password";

    //Connect to database
    SQLRETURN connReturn = SQLDriverConnect(hDbc, NULL, connection_string, SQL_NTS, NULL, 0, NULL,
                                            SQL_DRIVER_COMPLETE);

    //Allocate Statement Handle
    SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt);

    //Create statement
    SQLCHAR *query = (SQLCHAR *) "SELECT * FROM TEST;";
    SQLRETURN sqlPrepareResponse = SQLPrepare(hStmt, query, SQL_NTS); //strlen(reinterpret_cast<const char *>(query))

    //Bind columns
    SQLCHAR personName[20];
    SQLLEN personNameIndex;
    SQLRETURN bindNameResponse = SQLBindCol(hStmt, 2, SQL_C_CHAR, personName, sizeof(personName),
                                            &personNameIndex);


    SQLINTEGER personId;
    SQLLEN personIdIndex;
    SQLRETURN personIdBindResponse = SQLBindCol(hStmt, 1, SQL_INTEGER, &personId, 0, &personIdIndex);

    SQLRETURN execResponse = SQLExecute(hStmt);

    SQLRETURN fetchResponse;

    while ((fetchResponse = SQLFetch(hStmt)) != SQL_NO_DATA) {
        std::cout << "ID: [" << personId << "] :" << personName << std::endl;
    }


    /* Free the statement handle. */
    SQLFreeHandle(SQL_HANDLE_STMT, hStmt);

    /* Disconnect from the database. */
    SQLDisconnect(hDbc);

    /* Free the connection handle. */
    SQLFreeHandle(SQL_HANDLE_DBC, hDbc);

    /* Free the environment handle. */
    SQLFreeHandle(SQL_HANDLE_ENV, hEnv);

    return EXIT_SUCCESS;
}

答案 3 :(得分:0)

使用相似的代码,我有完全相同的错误(在Ubuntu 18.04中运行,但未更新至20.04)

cat /etc/odbcinst.ini
[ODBC Driver 17 for SQL Server]
Description=Microsoft ODBC Driver 17 for SQL Server
Driver=/opt/microsoft/msodbcsql17/lib64/libmsodbcsql-17.5.so.2.1
UsageCount=1

使用此连接字符串

DRIVER=ODBC Driver 17 for SQL Server;SERVER=127.0.0.1, 1433;UID=SA;PWD=password;DATABASE=my_database;

这是我的图书馆链接顺序

if(UNIX)
  find_program(LSB_RELEASE_EXEC lsb_release)
  execute_process(COMMAND ${LSB_RELEASE_EXEC} -is OUTPUT_VARIABLE LSB_RELEASE_ID_SHORT OUTPUT_STRIP_TRAILING_WHITESPACE)
  message(STATUS "Building in " ${LSB_RELEASE_ID_SHORT})
  if("${LSB_RELEASE_ID_SHORT}" STREQUAL "Ubuntu")
    message(STATUS "Linking with SQL-Server library")
    set(lib_dep ${lib_dep} msodbcsql-17)
  endif()
  set(lib_dep ${lib_dep} pthread odbc dl)
endif()

如上面的解决方案所述,更改链接顺序可以解决问题

set(lib_dep ${lib_dep} pthread odbc dl msodbcsql-17)