繁体   English   中英

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

[英]SQL Server 2016 CLR Stored Procedure Error : “A system assertion check has failed”

我试图通过C#程序集运行本机代码API(在C ++ .dll中),以便可以在SQL Server的CLR存储过程中使用某些API函数。 我尝试从C ++ dll使用的函数从数据历史记录程序访问原始数据,并以非托管类型返回数据。 然后将其留给C#程序集进行封送,并将结果通过管道传输到SQL 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]”中,并以UNSAFE模式将程序集添加到所需的SQL数据库中。 我还确保在SQL Server中启用了clr,并且在我正在使用的数据库中关闭TRUSTWORTHY。

但是,当我尝试调用使用C#程序集的存储过程时,出现以下问题。

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 CHECKDB,一切看起来都很好,所以这不是问题。 我已经复制了伦纳德的示例(从上面的链接),该示例基本上与我使用更简单的C ++ dll进行的过程相同。 该示例未发生任何错误,因此我认为SQL Server和C ++ API之间的appdomain存在一些竞争。

我的问题

这是我要尝试做的事吗? 我对使用CLR存储过程时SQL Server如何访问计算机内存并声明应用程序域一无所知,但似乎SQL Server和C ++ API之间存在一些有害的资源竞争。

下面显示的是C#程序集的两个部分(从C#框架对C ++ dll的调用和要由存储过程访问的类)。

从C ++导入C#DLL

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

[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();
}

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

是。 您不应该真正使用SQL CLR中的非托管DLL。 CLR托管代码是内存安全的,并且SQLCLR旨在保护SQL Server免受自定义托管代码引起的任何问题。 但是,如果使用非托管代码,则没有任何安全保证,并且这样做可能(很可能)使SQL Server崩溃。

而是从短暂的客户端进程(与SQL Server进程分开并短暂地)加载非托管DLL,以便在客户端进程终止时可以清除第3方DLL的任何内存问题。 SSIS是托管和运行此类内容的简单方法。

这是我要尝试做的事吗?

我不会说的“预期”这么多为“未预期”或“不应该被感到惊讶”。 该第三方库在隔离时显然可以做的很好,但在SQL Server的CLR主机中启动时则不能接受。 有充分的理由使SQL Server的CLR主机受到尽可能严格的限制。

因此,您应该做的是将此第3方C ++库和原始(且正在运行的)C#包装器作为Web Service托管在托管要连接到的服务“ IHU”的服务器上。 然后,对于您的SQLCLR代码,使用HttpWebRequestHttpWebResponse调用该Web服务。 SendResultsRow()循环中解析响应XML / JSON。

确保将更新后的SQLCLR代码的PERMISSION_SET设置为EXTERNAL_ACCESS因为您将不需要UNSAFE :-),并且在查询批处理中仍会获得相当即时的响应,而无需通过xp_cmdshell调用命令行或调用SSIS甚至安排工作来执行此操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM