(DelphiXE2および'gds32.dll' 10.0.1.335(ansi)がこの回答で使用されています)
dbExpressは、プロバイダー固有の操作をドライバーに委任する高レベルのフレームワークです。これらのプロバイダー固有のドライバーはすべて、同じ基本的な共通機能を公開しているため、この共通機能の範囲外の特定の情報を取得することはできません。
エラー報告に関しては、ドライバーは2つの関数をエクスポートします。mysql、mssql、その他のドライバーのいずれであっても、これらの関数はとDBXBase_GetErrorMessageLength
ですDBXBase_GetErrorMessage
。ドライバーは、クライアントライブラリから問題のほとんどを取得し、これらの関数を介してその情報をフレームワークに報告します。すでに報告されていることを超えて、データベースサーバーへの接続またはその他の操作で何がうまくいかなかったかについてのより具体的な詳細を取得することはできません。
したがって、winsockエラー情報を含めるかどうかはクライアントライブラリ次第です。質問に含まれているエラーの原因であるベース間ドライバーの場合、この情報はすでに含まれています(存在する場合)。
これは、既存のサーバーと、データベースサーバーによってリッスンされていないポートに接続する試みの例です。
Connection := TSQLConnection.Create(nil);
Connection.DriverName := 'Interbase';
Connection.Params.Values['Database'] := 'existingserver/80:database';
try
Connection.Open;
except
on E: TDBxError do begin
writeln(E.Message + sLineBreak);
出力は次のとおりです。
ホスト「existingserver:80」へのネットワーク要求を完了できません。
接続の確立に失敗しました。
お気づきのとおり、これは質問のエラーメッセージとまったく同じです。テキストにwinsockエラーがないことに注意してください。これは、ネットワークプロトコルに関する限り、winsockエラーが発生しないため、接続は実際に成功します。
これは既存のサーバーへの試みですが、リッスンされていないポートへの試みです。
Connection := TSQLConnection.Create(nil);
Connection.DriverName := 'Interbase';
Connection.Params.Values['Database'] := 'existingserver/81:database';
try
Connection.Open;
except
on E: TDBxError do begin
writeln(E.Message + sLineBreak);
返されたエラーは次のとおりです。
ホスト「existingserver:81」へのネットワーク要求を完了できません。
接続の確立に失敗しました。
不明なWin32エラー10060
今回は、特定のポートのリスナーがないため、接続が失敗します。クライアントライブラリが10060を解決できない理由はわかりませんが、これがwinsockエラーです。
ローカルホストの場合、リッスンされていないポート:
ホスト「localhost:3051」へのネットワーク要求を完了できません。
接続の確立に失敗しました。
ターゲットマシンが積極的に拒否したため、接続できませんでした。
ここに10061があります。
解決できないホストに接続しようとしても、gds32.dllはAPIエラーを報告しません。ライブラリがホストを解決する方法や、エラーコードが含まれていない理由はわかりませんが、エラーメッセージは冗長です。
「nonexistingserver」をホストするためのネットワーク要求を完了できません。
ホストマシンを見つけることができませんでした。
指定された名前がhostsファイルまたはドメインネームサービスに見つかりませんでした。
クライアントライブラリを直接使用する場合、APIエラーのみが発生する可能性があります。既存のサーバーと閉じたポートへの接続が試行される次のプログラムを調べます。
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
system.sysutils,
data.dbxcommon,
data.sqlexpr,
data.dbxinterbase;
function isc_attach_database(status_vector: PLongint; db_name_length: Smallint;
db_name: PAnsiChar; db_handle: PPointer; parm_buffer_length: Smallint;
parm_buffer: PAnsiChar): Longint; stdcall; external 'gds32.dll';
function isc_interprete(buffer: PAnsiChar; var status_vector: Pointer): Longint;
stdcall; external 'gds32.dll';
var
Connection: TSQLConnection;
StatusVector: array[0..19] of Longint;
Handle: PPointer;
Error: array[0..255] of AnsiChar;
IntrStatus: Pointer;
s: string;
begin
try
Connection := TSQLConnection.Create(nil);
Connection.DriverName := 'Interbase';
Connection.Params.Values['Database'] := 'server/3051:database'; // closed port
try
Connection.Open;
except
on E: TDBxError do begin
writeln(E.Message + sLineBreak);
if E.ErrorCode = TDBXErrorCodes.ConnectionFailed then begin
Handle := nil;
if isc_attach_database(@StatusVector, 0,
PAnsiChar(AnsiString(Connection.Params.Values['Database'])),
@Handle, 0, nil) <> 0 then begin
IntrStatus := @StatusVector;
s := '';
while isc_interprete(Error, IntrStatus) <> 0 do begin
s := s + AnsiString(Error) + sLineBreak;
if PLongint(IntrStatus)^ = 17 then // isc_arg_win32
s := s + ' --below is an api error--' + sLineBreak +
Format('%d: %s', [PLongint(Longint(IntrStatus) + 4)^,
SysErrorMessage(PLongint(Longint(IntrStatus) + 4)^)]) +
sLineBreak;
end;
Writeln(s);
end;
end else
raise;
end;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
どの出力:
ホスト「sever:3051」へのネットワーク要求を完了できません。
接続の確立に失敗しました。
不明なWin32エラー10060
ホスト「server:3051」へのネットワーク要求を完了できません。
接続の確立に失敗しました。
--以下はAPIエラーです-10060 :接続されたパーティが
一定期間後に
適切に応答しなかったために接続の試行が失敗したか、接続された
ホストが
不明なWin32エラー10060に応答できなかったために接続の確立に失敗しました
最初の段落はdbxが報告するものです。2番目の段落は、APIエラーコードとテキストの挿入を含む「gds32.dll」から取得したものです。それ以外は同じです。
上記は大まかなデモンストレーションであり、適切に入力するには「interbase.h」を使用します。また、考えられるAPIエラーの選択の詳細については、「ステータスベクトルの解析」または一般的に「エラー状態の処理」を参照してください。
いずれにせよ、ご覧のとおり、特定の情報を取得できるかどうかは、dbxがデータベースサーバーへの接続に使用するクライアントライブラリに完全に依存します。
一般的なケースでは、使用しているデータベースサーバーとは別にwinsockエラー情報を取得するには、データベース接続を開こうとする前にサーバーにソケットを接続してみて、これが成功した場合にのみテスト接続を閉じます。次に、データベースへの接続を続行します。これを行うには、任意のライブラリまたはベアAPIを使用できます。
簡単な例を次に示します。
function TestConnect(server: string; port: Integer): Boolean;
procedure WinsockError(step: string);
begin
raise Exception.Create(Format('"%s" fail. %d: %s:',
[step, WSAGetLastError, SysErrorMessage(WSAGetLastError)]));
end;
var
Error: Integer;
Data: TWSAData;
Socket: TSocket;
SockAddr: TSockAddrIn;
Host: PHostEnt;
begin
Result := False;
Error := WSAStartup(MakeWord(1, 1), Data);
if Error = 0 then begin
try
Socket := winsock.socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if Socket <> INVALID_SOCKET then begin
try
Host := gethostbyname(PAnsiChar(AnsiString(server)));
if Host <> nil then begin
SockAddr.sin_family := AF_INET;
SockAddr.sin_addr.S_addr := Longint(PLongint(Host^.h_addr_list^)^);
SockAddr.sin_port := htons(port);
if connect(Socket, SockAddr, SizeOf(SockAddr)) <> 0 then
WinsockError('connect')
else
Result := True;
end else
WinsockError('gethostbyname');
finally
closesocket(Socket);
end;
end else
WinsockError('socket');
finally
WSACleanup;
end;
end else
raise Exception.Create('winsock initialization fail');
end;
次のようなものを使用できます。
if TestConnect('server', 3050) then
//