進行状況メッセージを出力する印刷ステートメントを使用して、実行時間の長い Sybase ストアド プロシージャがいくつかあります。これらの SP は常に isql を使用して実行するか、aseisql または sqladvantage (すべて sybase 固有のツール) を使用して手動で実行してきました。これらのツールは、すべての SP に「set flushmessage on」が含まれているため、SP によって出力されるとすぐに印刷メッセージを正しく表示します。
一般的にプロシージャを実行して結果を変換する C# コンソール ラッパー アプリを作成しました。しかし、イライラすることに、印刷メッセージをキャプチャして標準出力に書き出すことができませんでした。これは些細なことのように思えますが、インターネット上であまり取り上げられないことに驚いています。
ODBC 接続を使用しており、必要なイベント ハンドラーを InfoMessage コールバック フックに追加しています。私のテストでは、これは print ステートメント メッセージで呼び出されますが、発行されたときにリアルタイムではありません。結果セットがクライアントに送り返されるまで呼び出されないようです。その後、すべてのメッセージで一度だけ呼び出されます。ExecuteNonQuery、ExecuteReaderなどを使用して、DataAdapterを使用してDataSetを埋めようとしましたが、動作は変わらないようです。また、Sybase System 11 と Adaptive Server Enterprise ODBC ドライバーの両方を試しましたが、違いはありませんでした。
だから私の質問は2つあります:
1)まず、ここで何が起こっているのかを正確に理解したいと思います-ストアドプロシージャがメッセージをデータベースサーバーにすぐに送信していることは知っていますが、明らかにどこかにキャッシュされています-ODBCドライバーによってサーバーから読み取られないか、読み取られてキャッシュされますドライバーメモリ自体に?- 通常、アプリ内の呼び出しスレッドがデータベース呼び出しをブロックしていると思いますが、実際に何が起こっているのかを考えようとすると、結果/メッセージをポーリングしているドライバー コード内でスレッドがビジー状態になっていると思いますが、その方法がわかりません。コールバック関数で動作し、それが処理されるとき。アプリでデバッグすると、結果を処理するために制御を戻す直前に呼び出されたようです。
2) 次に、私が本当に知りたいのは、メッセージがクライアントにすぐに送り返されるように動作を変更する方法があるかどうかです。
どんな助けでも大歓迎ですが、私は本当にこの問題を解決して理解するための具体的な助けを求めているので、「代わりにXYZの方法で物事をやらないのはなぜですか」という提案は控えてください - 問題が判明した場合、多くの代替案を考えることができます乗り越えられない。
コードを説明するための小さなテスト リグを次に示します。
ストアド プロシージャ:
create procedure sp_test
as
begin
set flushmessage on
print "Step 1"
waitfor delay "00:00:10"
print "Step 2"
waitfor delay "00:00:10"
select 10 as "number" -- preferably put some sort of select from a table here
print "Final Step"
end
go
grant execute on sp_test to public
go
.NET コード スニペット:
using System.Collections.Generic;
using System.Data;
using System.Data.Odbc;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
using (var conn = new OdbcConnection(@"<connection string here>"))
{
conn.InfoMessage += OnInfoMessage;
conn.Open();
var command = new OdbcCommand("sp_test", conn);
command.Timeout = 50000; // i added this later syntax might be wrong
var ds = new DataSet();
var da = new OdbcDataAdapter(command);
da.Fill(ds);
Console.ReadKey();
}
}
private static void OnInfoMessage(Object sender, OdbcInfoMessageEventArgs args)
{
foreach (OdbcError error in args.Errors)
{
Console.WriteLine(error.Message);
}
}
}
}