首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Server 2016 CLR存储过程错误:“系统断言检查失败”

Server 2016 CLR存储过程错误:“系统断言检查失败”
EN

Stack Overflow用户
提问于 2017-12-11 15:30:11
回答 2查看 776关注 0票数 1

我试图通过一个C++程序集运行一个本机代码API (在.dll中),以便在Server中的CLR存储过程中使用特定的C#函数。我试图从C++ dll中使用的函数访问来自数据历史学家的原始数据,并以非托管类型返回数据。然后由C#程序集将结果封送并将结果输送到Server。

我没有C++ dll的源代码,所以我真的不知道引擎盖下面到底发生了什么(它是第三方的)。但是,我可以在C#控制台应用程序中访问这些API函数,而不存在任何问题(我依赖https://lennilobel.wordpress.com/2014/01/29/calling-c-from-sql-clr-c-code/将C++ dll包装在.NET中)。我开发了一个工作的C#控制台应用程序,然后将它转换成一个类库,将类包装在"Microsoft.SqlServer.Server.SqlProcedure“中,并以不安全的模式将程序集添加到所需的SQL数据库中。我还确保在SQL服务器中启用了clr,并且在我正在使用的数据库中关闭了可信任的clr。

但是,当我试图调用使用C#程序集的存储过程时,会遇到以下问题。

代码语言:javascript
复制
Location:    AppDomain.cpp:2705
Expression:  hr != E_POINTER
SPID:        66
Process ID:  3584
Msg 3624, Level 20, State 1, Procedure sp_direct_proficy_api, Line 0 [Batch Start Line 2]
A system assertion check has failed. Check the SQL Server error log for details. Typically, an assertion failure is caused by a software bug or data corruption. To check for database corruption, consider running DBCC CHECKDB. If you agreed to send dumps to Microsoft during setup, a mini dump will be sent to Microsoft. An update might be available from Microsoft in the latest Service Pack or in a Hotfix from Technical Support.
Msg 596, Level 21, State 1, Line 2
Cannot continue the execution because the session is in the kill state.
Msg 0, Level 20, State 0, Line 2
A severe error occurred on the current command.  The results, if any, should be discarded.

我在系统断言检查上做了一些google搜索,并且发现它们通常是数据库损坏的结果。我已经运行了DBCC,一切看起来都很好,所以这不是问题。我复制了伦纳德的例子(从上面的链接),这基本上是相同的过程,我正在用一个简单得多的C++动态链接库。该示例没有出现错误,因此我认为Server和C++ API之间存在着对应用域的竞争。

我的问题

这是我想要做的事吗?我不太了解Server在使用CLR存储过程时是如何访问计算机内存和声明应用程序域的,但似乎Server和C++ API之间存在一些有害的资源竞争。

下面显示了C#程序集的两个部分(从C++工具调用C# dll和存储过程将要访问的类)。

C# DLL从C++导入

代码语言:javascript
复制
public class IHUAPI
{
const string DLLNAME = "IHUAPI.dll";

static class IHU64
{

    [DllImport(DLLNAME, CallingConvention = CallingConvention.StdCall, EntryPoint = "ihuConnect@16")]
    public static extern ihuErrorCode ihuConnect(string server, string username, string password, out int serverhandle);

    [DllImport(DLLNAME, CallingConvention = CallingConvention.StdCall, EntryPoint = "ihuReadRawDataByTime")]
    public static extern ihuErrorCode ihuReadRawDataByTime(int serverhandle, string tagname, ref IHU_TIMESTAMP start, ref IHU_TIMESTAMP end, out int numberOfSamples, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4, ArraySubType = UnmanagedType.LPStruct)] out IHU_DATA_SAMPLE[] samples);
}

public static ihuErrorCode ihuConnect(string server, string username, string password, out int serverhandle)
{

        return IHU64.ihuConnect(server, username, password, out serverhandle);
}

public static ihuErrorCode ihuReadRawDataByTime(int serverhandle, string tagname, IHU_TIMESTAMP start, IHU_TIMESTAMP end, out IHU_DATA_SAMPLE[] samples)
{
        int numberOfSamples;
        return IHU64.ihuReadRawDataByTime(serverhandle, tagname, ref start, ref end, out numberOfSamples, out samples);
}
}

存储过程中使用的C#程序集访问C++ API

代码语言:javascript
复制
[Microsoft.SqlServer.Server.SqlProcedure]
public static void API_Query(string tagname, DateTime start_date, DateTime end_date)
{

    int handle;
    ihuErrorCode result;
    result = IHUAPI.ihuConnect("houmseosprf007", "", "", out handle);
    IHU_DATA_SAMPLE[] values;
    IHU_TIMESTAMP start = new IHU_TIMESTAMP(start_date);
    IHU_TIMESTAMP end = new IHU_TIMESTAMP(end_date);

    ihuErrorCode result_api = IHUAPI.ihuReadRawDataByTime(handle, tagname, start, end, out values);

    SqlMetaData[] md = new SqlMetaData[3];
    md[0] = new SqlMetaData("tagname", SqlDbType.Text);
    md[1] = new SqlMetaData("return_value", SqlDbType.NVarChar, 50);
    md[2] = new SqlMetaData("timestamp", SqlDbType.DateTime);
    SqlDataRecord row = new SqlDataRecord(md);
    SqlContext.Pipe.SendResultsStart(row);

    DateTime p;
    string p2;

    for (int i = 1; i < (values == null ? 0 : values.Length); i++)
    {

        using (IHU_DATA_SAMPLE sample = values[i])
        {
            if (sample.ValueDataType != ihuDataType.Array)
            {
                p = sample.TimeStamp.ToDateTime();
                p2 = sample.ValueObject.ToString();
                row.SetValue(0, tagname);
                row.SetValue(1, p2);

                row.SetValue(2, p);

            }
            else
            {

                p = sample.TimeStamp.ToDateTime();
                ihuArrayValue aValue = (ihuArrayValue)Marshal.PtrToStructure(sample.Value.ArrayPtr, typeof(ihuArrayValue));
                p2 = aValue.GetArrayValue.ToString();
                row.SetValue(0, tagname);
                row.SetValue(1, p2);
                row.SetValue(2, p);


            }
        }

        SqlContext.Pipe.SendResultsRow(row);
    }

    SqlContext.Pipe.SendResultsEnd();
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-12-11 16:18:42

这是我想要做的事吗?

我不会说“期望”而不是“非_un_expected",或者”不应该对此感到惊讶“。这个第三方库显然是在做一些在隔离时很好的事情,但是当它从SQL Server的CLR主机中启动时,它是不可接受的。SQL Server的CLR主机有很好的理由受到如此严格的限制。

因此,您应该做的是将这个第三方C++库和您最初的(并且正在工作的) C#包装器作为一个运行在承载您所连接的服务的服务器上的working,"IHU“。然后,对于SQLCLR代码,使用HttpWebRequestHttpWebResponse调用该web服务。在SendResultsRow()循环中解析响应XML / JSON。

确保将更新后的SQLCLR代码的PERMISSION_SET设置为EXTERNAL_ACCESS,因为您不需要UNSAFE :-),并且您仍然可以在查询批处理中获得相当即时的响应,而不需要通过xp_cmdshell调用命令行,或者调用SSIS,甚至调度任务来执行它。

票数 1
EN

Stack Overflow用户

发布于 2017-12-11 15:51:58

Server与C++ API之间似乎存在一些有害的资源竞争。

是。您不应该真正使用SQL中的非托管DLL。CLR托管代码是内存安全的,SQLCLR的设计是为了保护Server免受自定义托管代码引起的任何问题的影响。但是,如果使用非托管代码,则没有任何安全保证,而且很有可能(很可能)会使Server崩溃。

相反,从一个与Server进程分离的短期客户端进程加载非托管DLL,并使第三方DLL的任何内存问题在客户端进程终止时都能被清除。SSIS是托管和运行类似东西的简单方法。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47756168

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档