2017-12-11 7 views
1

CLRで特定のAPI関数を使用できるように、C#アセンブリを使用してネイティブコードAPI(C++ .dll)を実行しようとしていますSQL Serverのストアドプロシージャ私がC++ dllから使用しようとしている関数は、データヒストリアンの生データにアクセスし、アンマネージ型のデータを返します。その後、C#アセンブリに残してマーシャリングし、結果をSQL Serverにパイプします。SQL Server 2016 CLRストアドプロシージャエラー:「システムアサーションチェックに失敗しました」

私はC + +のDLLのソースコードを持っていないので、実際にはフードの下(サードパーティ製)で正確に何が起こっているのか分かりません。しかし、私は問題なくC#コンソールアプリでこれらのAPI関数にアクセスすることができます(私はhttps://lennilobel.wordpress.com/2014/01/29/calling-c-from-sql-clr-c-code/に.NETのC++ dllをラッピングすることに頼っていました)。私は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を実行しており、すべてが正常に見えるので、これは問題ではありません。私は、上記のリンクからのLeonardの例を、私がはるかに単純なC++のdllで取り組んでいるのと本質的に同じプロセスであると複製しました。この例ではエラーは発生しなかったので、SQL ServerとC++ APIの間にappdomainの競合があると思います。

私の質問

が、これは私がしようとしています何のために予想される問題ですか? CLRストアドプロシージャを使用すると、SQL Serverがコンピュータのメモリにアクセスし、appdomainを要求する方法について多くのことはわかりませんが、SQL ServerとC++ APIの間でリソースの競合があるようです。

以下に、C#アセンブリの2つの部分(C#のハーネスからの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(); 
} 

答えて

1

これは私がやろうとしていることで期待される問題ですか?

私は「国連は期待できない」として、そんなに「期待」と言うではないでしょうか「に驚かれるべきではありません」。そのサードパーティライブラリは、SQL ServerのCLRホストから開始されたときに、分離されたときには問題ないが、受け入れられないものを明確に実行しています。 SQL ServerのCLRホストが制限されているのは正当な理由があります。

代わりに、このサードパーティのC++ライブラリと、元の(動作している)C#ラッパーを、接続しているサービス「IHU」をホストするサーバー上で動作するWebサービスとしてホストする必要があります。次に、SQLCLRコードの場合は、HttpWebRequestHttpWebResponseを使用して、そのWebサービスを呼び出します。ループSendResultsRow()の応答XML/JSONを解析します。

あなたがUNSAFE :-)を必要としないので、ちょうどEXTERNAL_ACCESSに更新SQLCLRコードのPERMISSION_SETを必ず設定してください、とあなたはまだコマンドを呼び出すために支払うために必要とすることなく、あなたのクエリ・バッチでかなり瞬時の応答を取得しますSSHを起動したり、ジョブのスケジューリングを行ったりすることもできます。

+0

良いアドバイス。ストアドプロシージャを使用してSQL ServerインスタンスをホストするボックスでWebサービスをホストするのと同じ問題が発生しますか? – bidout

+0

私は信じられませんが、テストする必要があります。同じサーバーを使用しても問題ありませんが、SQL Serverが実際に何をするかは、それが何をするかについての意見よりも重要です。 "IHU"サービスがSQL Serverと同じサーバー上に既に存在する場合は、このWebサービスを実行して、リモートサービスが元のサーバーにコールバックするようにネットワークを呼び出さないようにします。しかし、 "IHU"が別のサーバー上にある場合は、SQL Serverが取得できる物理RAMの量が多くなるので、Webサーバーに格納することを選択します。 –

+0

アンマネージドコード部分用のWeb APIをまとめました。ストアドプロシージャはクライアントを呼び出し、クライアントはC++ dllを呼び出すWeb APIを呼び出します。ストアドプロシージャを実行するのと同じコンピュータでホストをテストしましたが、これまで問題なく動作していました。上記のRAMの理由から、APIサーバーを別のサーバーに移行することになります。 – bidout

1

SQL ServerとC++ APIの間にいくつかの有害なリソース競合があるようです。

はい。 SQL CLRからアンマネージDLLを実際に使用すべきではありません。 CLR管理コードはメモリ保護されており、SQLCLRはカスタム管理コードから発生するあらゆる問題からSQL Serverを保護するように設計されています。ただし、アンマネージコードを使用する場合、安全性の保証はなく、SQL Serverをクラッシュさせる可能性があります(可能性があります)。

代わりに、SQL Serverプロセスとは別の短命のクライアントプロセスからアンマネージドDLLを読み込み、クライアントプロセスが終了したときにサードパーティDLLのメモリ問題がすべて消去されるように短命にします。 SSISはこのようなものをホストし実行する簡単な方法です。

関連する問題