2つの異なる接続文字列を一緒に比較し、それらが同じ情報であるかどうかを識別できるようにする必要があります。プロパティのレイアウトが異なる可能性があるため、単純な文字列比較を行うことはできませんが、それでも同じ接続を表します。
私が行ってこれについて自分の比較を書く前に、これを行うことができる何かがすでにありますか?
私は方法を探しましたが、これについては何も見つかりません。
2つの異なる接続文字列を一緒に比較し、それらが同じ情報であるかどうかを識別できるようにする必要があります。プロパティのレイアウトが異なる可能性があるため、単純な文字列比較を行うことはできませんが、それでも同じ接続を表します。
私が行ってこれについて自分の比較を書く前に、これを行うことができる何かがすでにありますか?
私は方法を探しましたが、これについては何も見つかりません。
IDataInitialize::GetDataSource
指定された接続文字列から初期化されていないデータソースオブジェクトを返すメソッドを使用できます。このメソッドは、あるタイプのデータソースオブジェクトへのポインタを返すIUnknown
ため、2つの比較された接続文字列に対して取得されたオブジェクトを直接比較することはできません。ただし、これらの初期化されていないデータソースオブジェクトyou can query
のIDBProperties
インターフェイスにより、特定のプロバイダーでサポートされているすべてのプロパティにアクセスできるようになります。
プロパティセットを取得するには、メソッドを使用する必要がありますIDBProperties::GetProperties
。これにより、要素(プロパティ)DBPROPSET
の配列を含む構造が返されます。DBPROP
次に、この配列を繰り返し処理し、必要な方法でこれら2つのデータソースオブジェクトのプロパティを比較します。
次のIsSameConnStr
関数は、接続文字列が等しい場合はTrueを返し、そうでない場合はFalseを返します。使用されるプロパティ値の比較では、大文字と小文字が区別されるプロパティを除いて、大文字と小文字が区別されないことに注意してくださいDBPROP_AUTH_PASSWORD
。
uses
ActiveX, ComObj, OleDB;
function IsSameVarWideStr(const AValue1, AValue2: OleVariant;
ACaseSensitive: Boolean = False): Boolean;
begin
Result := VarType(AValue1) = VarType(AValue2);
if Result then
begin
if ACaseSensitive then
Result := WideCompareStr(VarToWideStr(AValue1),
VarToWideStr(AValue2)) = 0
else
Result := WideCompareText(VarToWideStr(AValue1),
VarToWideStr(AValue2)) = 0;
end;
end;
function IsSameConnStr(const AConnStr1, AConnStr2: WideString): Boolean;
var
I: Integer;
DataSrc1: IUnknown;
DataSrc2: IUnknown;
DataInit: IDataInitialize;
PropSet1: PDBPropSet;
PropSet2: PDBPropSet;
PropSetCnt1: ULONG;
PropSetCnt2: ULONG;
Properties1: IDBProperties;
Properties2: IDBProperties;
const
DBPROP_AUTH_PASSWORD = $00000009;
begin
// first check if the input connection strings aren't exactly the same
Result := CompareStr(AConnStr1, AConnStr2) = 0;
// if they are not same, then...
if not Result then
begin
// create IDataInitialize object instance
OleCheck(CoCreateInstance(CLSID_DataLinks, nil, CLSCTX_INPROC_SERVER or
CLSCTX_LOCAL_SERVER, IID_IDataInitialize, DataInit));
// get data source objects for both input connection strings
OleCheck(DataInit.GetDataSource(nil, CLSCTX_INPROC_SERVER,
PWideChar(AConnStr1), IUnknown, DataSrc1));
OleCheck(DataInit.GetDataSource(nil, CLSCTX_INPROC_SERVER,
PWideChar(AConnStr2), IUnknown, DataSrc2));
// query for IDBProperties objects of the data source objects
if Succeeded(DataSrc1.QueryInterface(IID_IDBProperties, Properties1)) and
Succeeded(DataSrc2.QueryInterface(IID_IDBProperties, Properties2)) then
begin
// get properties of data source objects
OleCheck(Properties1.GetProperties(0, nil, PropSetCnt1, PropSet1));
OleCheck(Properties2.GetProperties(0, nil, PropSetCnt2, PropSet2));
try
// same DB provider will have the same set of initialization properties,
// so the first check might be the property count, if that differs, then
// at least DB provider is different, so if this equals, then...
if PropSetCnt1 = PropSetCnt2 then
begin
// initialize positive result
Result := True;
// iterate all the properties
for I := 0 to PropSet1.cProperties - 1 do
begin
// check if we're comparing the same property and if so, compare the
// property values; for password property compare the value with case
// sensitivity, for all the others case insensitively; if any of this
// doesn't match, we're done with False result and we can exit
if (PropSet1.rgProperties[I].dwPropertyID <>
PropSet2.rgProperties[I].dwPropertyID) or
not IsSameVarWideStr(PropSet1.rgProperties[I].vValue,
PropSet2.rgProperties[I].vValue,
PropSet1.rgProperties[I].dwPropertyID = DBPROP_AUTH_PASSWORD) then
begin
Result := False;
Break;
end;
end;
end;
finally
// release the property sets; note that you should avoid this common
// try..finally block and that you should free also each property array
// element by using IMalloc::Free; why I've used CoTaskMemFree see this
// question http://stackoverflow.com/q/3079508/960757
CoTaskMemFree(PropSet1);
CoTaskMemFree(PropSet2);
end;
end;
end;
end;
使用法は明らかだと思うので、いくつかの接続文字列の結果について説明します。
IsSameConnStr = True
AConnStr1: Provider=MSDASQL.1;Persist Security Info=True;Data Source=datasource
AConnStr2: Provider=MSDASQL.1;Persist Security Info=True;Data Source=DATASOURCE
IsSameConnStr = True
AConnStr1: Provider=MSDASQL.1;Data Source=datasource;Persist Security Info=True
AConnStr2: Provider=MSDASQL.1;Persist Security Info=True;Data Source=DATASOURCE
IsSameConnStr = True
AConnStr1: Provider=MSDASQL.1;Password=PASSWORD;Data Source=datasource;Persist Security Info=True
AConnStr2: Provider=MSDASQL.1;Data Source=DATASOURCE;Password=PASSWORD;Persist Security Info=True
IsSameConnStr = False - password differs in case sensitivity
AConnStr1: Provider=MSDASQL.1;Password=PASSWORd;Data Source=datasource;Persist Security Info=True
AConnStr2: Provider=MSDASQL.1;Data Source=DATASOURCE;Password=PASSWORD;Persist Security Info=True
プロパティのコレクションを取得するには、にをConnectionString
割り当て(実際にはDBに接続せずに)、コレクションを使用できます(コレクションアイテムは)。例:ConnectionString
TADOConnection
TADOConnection.Properties
ADOInt.Property_
ADOConnection.Properties.Get_Item('Data Source')
おそらく、特定のプロパティを比較して、接続が特定のプロバイダーを介して特定のデータストアに設定されているかどうかを判断する必要があります。例:、、、
Provider
\ (Data Source
オプション)。Initial Catalog
User ID
Password
プロバイダーによっては無視したいプロパティがたくさんあります。例:
Workstation ID
、、、、Persist Security Info
など。Use Procedure for Prepare
Auto Translate
TADOConnection
プロパティコレクションを反復処理する方法の例を次に示します。
var
ADOConnection: TADOConnection;
PropName, PropValue: WideString;
I: Integer;
ADOConnection := TADOConnection.Create(nil);
try
ADOConnection.ConnectionString := 'Provider=MSDASQL.1;Password=secret;Data Source=127.0.0.1;User ID=user;Initial Catalog=mycatalog';
for I := 0 to ADOConnection.Properties.Count - 1 do
begin
// Properties.Item[I] is ADOInt.Property_
PropName := ADOConnection.Properties.Item[I].Name;
PropValue := VarToWideStr(ADOConnection.Properties.Item[I].Value);
ShowMessage(Format('%s=%s', [PropName, PropValue]));
end;
finally
ADOConnection.Free;
end;
ConnectionString
DBに接続した後 に追加/変更されるプロパティがはるかに多い可能性があるTADOConnection
ため、これを考慮する必要があります。