CLR에서 특정 API 함수를 사용할 수 있도록 C# 어셈블리를 통해 네이티브 코드 API (C++ .dll)를 실행하려고합니다. SQL Server의 저장 프로 시저. C++ dll에서 사용하려고 시도하는 함수는 데이터 기록자의 원시 데이터에 액세스하고 관리되지 않는 형식의 데이터를 반환합니다. 그런 다음 결과를 SQL Server에 마샬링하고 파이프하기 위해 C# 어셈블리에 남아 있습니다.SQL Server 2016 CLR 저장 프로 시저 오류 : "시스템 어설 션 검사가 실패했습니다"
저는 C++ dll에 대한 소스 코드가 없으므로, 실제적으로 후드 (써드 파티)가 정확히 무엇인지 모릅니다. 그러나 C# 콘솔 앱에서이 API 함수에 문제없이 액세스 할 수 있습니다 (.NET에서 C++ dll을 래핑하기 위해 https://lennilobel.wordpress.com/2014/01/29/calling-c-from-sql-clr-c-code/에 의존했습니다). C# 콘솔 응용 프로그램을 개발 한 다음 클래스 라이브러리로 변환하고 "[Microsoft.SqlServer.Server.SqlProcedure]"클래스를 래핑하고 UNSAFE 모드에서 원하는 SQL 데이터베이스에 어셈블리를 추가했습니다. 또한 clr이 SQL 서버에서 활성화되어 있고 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를 실행 했으므로 문제가되지 않습니다. 필자는 Leonard의 예제 (위의 링크에서 본)를 본질적으로 훨씬 단순한 C++ dll로 착수 한 것과 동일한 프로세스로 복제했습니다. 이 예제에서는 오류가 발생하지 않았으므로 SQL Server와 C++ API간에 appdomain에 대한 경쟁이 존재한다고 생각합니다.
내 질문
이 내가 할 시도하고있는 무슨에 대한 예상 문제인가? CLR 저장 프로 시저를 사용할 때 SQL Server가 컴퓨터 메모리에 액세스하고 appdomain을 요청하는 방법에 대해 많이 알지 못하지만 SQL Server와 C++ API간에 몇 가지 유해한 리소스 경쟁이있는 것처럼 보입니다.
다음은 C# 어셈블리의 두 부분 (C# harness에서 C++ dll을 호출하고 저장 프로 시저에서 액세스 할 클래스)입니다. 액세스 C에 저장 프로 시저에 사용되는 C++
public class IHUAPI
{
const string DLLNAME = "IHUAPI.dll";
static class IHU64
{
[DllImport(DLLNAME, CallingConvention = CallingConvention.StdCall, EntryPoint = "[email protected]")]
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# DLL 가져 오기 ++ 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 인스턴스를 호스팅하는 상자에서 웹 서비스를 호스팅하는 것과 동일한 문제가 발생합니까? – bidout
나는 믿지 않는다.하지만 시험해보아야 할 것이다. 같은 서버를 사용하는 것이 좋지만 SQL Server가 실제로하는 일은 어떤 일을 할 수 있는지에 대한 의견보다는 더 중요합니다. "IHU"서비스가 SQL Server와 동일한 서버에 이미있는 경우이 웹 서비스를 실행하여 원격 서비스에서 원래 서버로 다시 전화를 걸도록 네트워크를 호출하지 않아도됩니다. . 그러나 "IHU"가 별도의 서버에 있다면 SQL Server가 얻을 수있는만큼의 실제 RAM을 선호하므로 웹 서비스에서 낭비하는 이유는 무엇입니까? –
비 관리 코드 부분에 대한 웹 API를 작성했습니다. 저장 프로시 저는 클라이언트를 호출하고 클라이언트는 C++ dll을 호출하는 웹 API를 호출합니다. 저장 프로 시저를 실행하는 동일한 컴퓨터에서 호스팅을 테스트했으며 지금까지 문제없이 작동했습니다. 위에서 언급 한 RAM상의 이유 때문에 API 서버를 다른 서버로 마이그레이션하게 될 것입니다. – bidout