c # — Ошибка хранимой процедуры CLR в SQL Server 2016: «Проверка системного утверждения не выполнена».

Я пытаюсь запустить API Native Code (в C ++ .dll) через сборку C #, чтобы я мог использовать определенные функции API в хранимой процедуре CLR в SQL Server. Функция, которую я пытаюсь использовать из DLL C ++, получает доступ к необработанным данным из исторического источника данных и возвращает данные в неуправляемых типах. Затем он оставляется сборке C # для маршалинга и передачи результатов на SQL Server.

У меня нет исходного кода для C ++ dll, поэтому я действительно не знаю, что именно происходит под капотом (он сторонний). Тем не менее, я могу получить доступ к этим функциям API в консольном приложении C # без проблем (я полагался на https://lennilobel.wordpress.com/2014/01/29/calling-c-from-sql-clr-c-code/ для упаковки C ++ DLL в .NET). Я разработал работающее консольное приложение C #, затем превратил его в библиотеку классов, обернул класс в «[Microsoft.SqlServer.Server.SqlProcedure]» и добавил сборку в нужную базу данных SQL в режиме UNSAFE. Я также удостоверился, что 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, и все выглядит хорошо, так что это не проблема. Я повторил пример Леонарда (из приведенной выше ссылки), который по сути является тем же процессом, который я выполняю с гораздо более простой C ++ dll. В этом примере ошибок не возникало, поэтому я считаю, что существует некоторая конкуренция за домен приложений между SQL Server и C ++ API.

Мой вопрос

Это ожидаемая проблема для того, что я пытаюсь сделать? Я не очень много знаю о том, как SQL Server получает доступ к памяти компьютера и утверждает домены приложений при использовании хранимых процедур CLR, но создается впечатление, что между SQL Server и C ++ API существует некоторая вредоносная конкуренция за ресурсы.

Ниже показаны две части сборки C # (вызов библиотеки C ++ из жгута проводов C # и класса, к которому должен обращаться хранимая процедура).

C # DLL Импорт из C ++

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

1

Решение

Это ожидаемая проблема для того, что я пытаюсь сделать?

Я бы не сказал «ожидал» так много, как «нет» ООНожидается «, или» не должен удивляться «. Эта сторонняя библиотека явно делает что-то, что хорошо, когда она изолирована, но неприемлемо, когда она инициируется из узла CLR SQL Server. Есть веская причина для CLR SQL Server хост должен быть настолько ограничен, насколько это возможно.

Итак, вместо этого вам следует разместить эту стороннюю библиотеку C ++ и вашу оригинальную (и работающую) оболочку C # в качестве веб-службы, работающей на сервере, на котором размещается служба, к которой вы подключаетесь, «IHU». Затем для вашего кода SQLCLR используйте HttpWebRequest а также HttpWebResponse позвонить в этот веб-сервис. Разобрать ответ XML / JSON в SendResultsRow() петля.

Обязательно установите PERMISSION_SET обновленного кода SQLCLR, чтобы он был просто EXTERNAL_ACCESS как вам не нужно UNSAFE :-), и вы по-прежнему получаете довольно мгновенный ответ в вашем пакете запросов без необходимости раскошелиться на вызов командной строки через xp_cmdshell или вызывая SSIS или даже планируя работу, чтобы сделать это.

1

Другие решения

создается впечатление, что между SQL Server и C ++ API существует некая вредоносная конкуренция за ресурсы.

Да. Вы не должны действительно использовать неуправляемые библиотеки DLL из SQL CLR. Управляемый код CLR безопасен для памяти, а SQLCLR спроектирован для защиты SQL Server от любых проблем, возникающих из пользовательского управляемого кода. Однако если вы используете неуправляемый код, у вас нет никаких гарантий безопасности, и вполне возможно (вероятно), что вы можете аварийно завершить работу SQL Server.

Вместо этого загрузите неуправляемую DLL из недолговечного клиентского процесса, отдельного от процесса SQL Server, и недолговечного, чтобы любые проблемы с памятью сторонней DLL могли быть устранены после завершения клиентского процесса. SSIS — это простой способ размещения и запуска подобных вещей.

1

По вопросам рекламы [email protected]