从SQL Server数据库中的CLR代码打开到DB2数据库的连接

0pizxfdo  于 2022-11-07  发布在  DB2
关注(0)|答案(1)|浏览(194)

我试图从SQLServer数据库中的CLR方法连接到DB2数据库。连接是通过OleDbConnection完成的。以前这种方法是有效的,但我们正在迁移到一个新的环境。我们过去使用IBM DB2 9.7驱动程序在SQL Server 2014上工作。现在,我们将使用最新的IBM DB2 11.5驱动程序在SQL Server 2019上工作。开发工作在中完成。NET Framework 4.8并使用CLR 4.0。由于更新了环境,我们现在在发布之前使用证书对CLR程序集进行签名。
CLR代码本身可以工作并且可以被调用,但是到DB2数据库的OleDbConnection不能工作。当运行OleDbConnection.Open()方法时,我们得到以下错误:

A .NET Framework error occurred during execution of user-defined routine or aggregate "clrGetData":
System.Data.OleDb.OleDbException: Unspecified error
System.Data.OleDb.OleDbException:
  at System.Data.OleDb.OleDbServicesWrapper.GetDataSource(OleDbConnectionString constr, DataSourceWrapper& datasrcWrapper)
  at System.Data.OleDb.OleDbConnectionInternal..ctor(OleDbConnectionString constr, OleDbConnection connection)
  at System.Data.OleDb.OleDbConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningObject)
  at System.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup, DbConnectionOptions userOptions)
  at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
  at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
  at System.Data.ProviderBase.DbConnectionInternal.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
  at System.Data.OleDb.OleDbConnection.Open()

奇怪的是,当我创建一个简单的控制台应用程序,试图通过OleDb连接到同一个数据库时,使用相同的连接字符串和相同的代码来初始化连接等,连接打开时没有问题,并且可以调用DB2数据库。(它调用SQL Server数据库上的CLR方法)和数据库服务器(CLR在其上运行并与DB2数据库建立连接)。
我还尝试通过将CLR代码复制到Web应用程序,直接从应用服务器上的Web应用程序连接到DB2数据库。这也没有任何问题。但是,由于我们当前的设置需要从数据库初始化两个数据库之间的同步,因此要完全替换CLR过程将需要大量的重构工作。
这是我们目前正在测试的CLR过程的一个示例:

[Microsoft.SqlServer.Server.SqlProcedure]
public static void clrGetData(string userId)
{
    var connectionString = <Get connection string to DB2 database>;
    using (var db2connection = new OleDbConnection(connectionString))
    {
        db2connection.Open();

        if (db2connection == null) throw new ArgumentNullException("connection");

        Microsoft.SqlServer.Server.SqlMetaData[] mdDos = new Microsoft.SqlServer.Server.SqlMetaData[1];
        mdDos[0] = new Microsoft.SqlServer.Server.SqlMetaData("Profile", System.Data.SqlDbType.VarChar, 100);

        string storedProcedure = string.Format("<Name of SP on DB2 database>");

        var cmd = new DB2Command();

        cmd.CommandText = storedProcedure;
        cmd.CommandType = System.Data.CommandType.StoredProcedure;
        cmd.Connection = db2connection;

        // parameters
        OleDbParameter dbParam;
        dbParam = new OleDbParameter("<name>", OleDbType.Char, 10, "<srcColumn>");
        dbParam.Value = userId;
        dbParam.Direction = ParameterDirection.Input;
        cmd.Parameters.Add(dbParam);

        // Some other input parameters
        // ...

        dbParam = new OleDbParameter("<name>", DB2Type.Integer, 10, "<srcColumn>");
        dbParam.Direction = ParameterDirection.Output;
        cmd.Parameters.Add(dbParam);

        // Some other output parameters
        // ...

        var reader = cmd.ExecuteReader();

        Microsoft.SqlServer.Server.SqlPipe sqlpipe = Microsoft.SqlServer.Server.SqlContext.Pipe;
        Microsoft.SqlServer.Server.SqlDataRecord record = new Microsoft.SqlServer.Server.SqlDataRecord(mdDos);

        sqlpipe.SendResultsStart(record);

        if (reader.Read())
        {
            record.SetValue(0, reader[5]);

            sqlpipe.SendResultsRow(record);
        }
        sqlpipe.SendResultsEnd();
        reader.Close();
        db2connection.Close();
    }
}

我已经扩展了控制台测试应用程序,使其也与OdbcConnection和DB2 Connection连接(通过引用IBM驱动程序中使用的IBM.Data.DB2.dll)。我使它们也都连接起来,但是当在CLR过程中使用它时,我又一次卡住了。
当使用Odbc时,我得到以下错误:

SqlException (0x80131904): A .NET Framework error occurred during execution of user-defined routine or aggregate "clrGetData": 
System.Data.Odbc.OdbcException: ERROR [IM003] Specified driver could not be loaded due to system error  1114: A dynamic link library (DLL) initialization routine failed. (IBM DB2 ODBC DRIVER - DB2COPY1, D:\Program Files\IBM\SQLLIB\BIN\DB2CLIO.DLL).
System.Data.Odbc.OdbcException: 
   at System.Data.Odbc.OdbcConnection.HandleError(OdbcHandle hrHandle, RetCode retcode)
   at System.Data.Odbc.OdbcConnectionOpen..ctor(OdbcConnection outerConnection, OdbcConnectionString connectionOptions)
   at System.Data.Odbc.OdbcConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup, DbConnectionOptions userOptions)
   at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at System.Data.ProviderBase.DbConnectionInternal.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.Odbc.OdbcConnection.Open()

在使用IBM dll时,我们遇到了一些问题,因为我们不能在不将外部引用作为程序集添加到SQL Server的情况下添加外部引用。由于IBM驱动程序本身可能引用了大量其他不受支持的引用,这将是一个需要解决的完全不同的问题。
下面是我们为每个方法使用的连接字符串:

// OleDb:
Provider=IBMDADB2.DB2COPY1;Database=<DB Name>;Hostname=<IP Address>;Protocol=TCPIP;Port=<Port Number>;Uid=<Username>;Pwd=<Password>;

// Odbc:
Driver={IBM DB2 ODBC DRIVER - DB2COPY1};Database=<DB Name>;Hostname=<IP Address>;Port=<Port Number>;Protocol=TCPIP;UID=<Username>;PWD=<Password>;

// IBM DB2:
Server=<IP Address>:<Port Number>;Database=<DB Name>;UID=<Username>;PWD=<Password>;

我试过在谷歌上搜索很多这样的问题,但是谷歌在这方面不是我的朋友,而且似乎还没有解决方案。
在SQL Server的CLR过程中连接到DB2数据库的最佳方法是什么?我们的设置/代码可能有什么问题?

编辑:

正如下面的评论者所问,db2level命令的输出:

D:\Program Files\IBM\SQLLIB\BIN>db2level
DB21085I  This instance or install (instance name, where applicable: "DB2")
uses "64" bits and DB2 code release "SQL11050" with level identifier
"0601010F".
Informational tokens are "DB2 v11.5.0.1077", "s1906101300",
"DYN1906101300WIN64", and Fix Pack "0".
Product is installed at "D:\Program Files\IBM\SQLLIB" with DB2 Copy Name
"DB2COPY1".

解决方案:

解决方案分为两部分:

  1. 11.5.0 IBM DB2客户端在加载DB2CLIO.dll文件时出现问题:(https://www.ibm.com/support/pages/apar/IT30451)。因此,已在数据库服务器上安装了最新的修复补丁程序。
  2. MSSQLSERVER用户被添加到DB2用户的Windows组中,以解决权限问题。
kulphzqa

kulphzqa1#

解决人:

  • 确保安装了Db2胖客户端的最新补丁包(以前安装的是补丁包0,通常不适用于生产)。
  • 确保用于连接到Db2(从MS-SQLServer)的用户ID是正确的loca/ldap/ActiveDirectory组的成员,该组赠款了对Db2数据库及其对象的所需访问权限。

经常检查IBM数据库产品和驱动程序的最新补丁包,这些都可以从补丁包中心网站下载。

相关问题