有什么简单的方法可以比较连接字符串而不自己解析吗? [英] Is there any simple way to compare connection strings without parsing it myself?

查看:73
本文介绍了有什么简单的方法可以比较连接字符串而不自己解析吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要能够将两个不同的连接字符串一起比较,并确定它们是否是相同的信息。我无法进行简单的字符串比较,因为属性的布局可以不同,但​​仍表示相同的连接。



在开始编写自己的比较之前,



我已经找到了一种方法,但找不到任何相关方法。

解决方案

您可以使用 IDataInitialize :: GetDataSource 方法,该方法从给定的连接字符串返回未初始化的数据源对象。由于此方法返回指向 IUnknown 类型的数据源对象的指针,因此无法直接比较从两个比较的连接字符串获得的对象。但是, 您可以查询 IDBProperties 接口在那些未初始化的数据源对象上,这使您可以访问给定提供程序支持的所有属性。 / p>

要获取属性集,您需要使用 IDBProperties :: GetProperties 方法。这将返回 DBPROPSET 结构,其中包含一个 DBPROP 元素(属性)。然后,您将简单地迭代此数组并以您需要的方式比较这两个数据源对象的属性。



以下 IsSameConnStr 函数返回True,否则返回False。请注意,除了 DBPROP_AUTH_PASSWORD 属性,并将其与区分大小写进行比较:

 使用
ActiveX,ComObj,OleDB;

函数IsSameVarWideStr(const AValue1,AValue2:OleVariant;
ACaseSensitive:Boolean = False):布尔值;
开始
结果:= VarType(AValue1)= VarType(AValue2);
如果结果然后
开始
如果ACaseSensitive然后
结果:= WideCompareStr(VarToWideStr(AValue1),
VarToWideStr(AValue2))= 0
else
结果:= WideCompareText(VarToWideStr(AValue1),
VarToWideStr(AValue2))= 0;
结尾;
结尾;

函数IsSameConnStr(const AConnStr1,AConnStr2:WideString):布尔值;
var
I:整数;
DataSrc1:IUnknown;
DataSrc2:IUnknown;
DataInit:IDataInitialize;
PropSet1:PDBPropSet;
PropSet2:PDBPropSet;
PropSetCnt1:ULONG;
PropSetCnt2:ULONG;
属性1:IDB属性;
属性2:IDB属性;
const
DBPROP_AUTH_PASSWORD = $ 00000009;
begin
//首先检查输入的连接字符串是否不完全相同
结果:= CompareStr(AConnStr1,AConnStr2)= 0;
//如果不相同,则...
如果不相同,则
开始
//创建IDataInitialize对象实例
OleCheck(CoCreateInstance(CLSID_DataLinks,nil ,CLSCTX_INPROC_SERVER或
CLSCTX_LOCAL_SERVER,IID_IDataInitialize,DataInit));
//获取两个输入连接字符串的数据源对象
OleCheck(DataInit.GetDataSource(nil,CLSCTX_INPROC_SERVER,
PWideChar(AConnStr1),IUnknown,DataSrc1));
OleCheck(DataInit.GetDataSource(nil,CLSCTX_INPROC_SERVER,
PWideChar(AConnStr2),IUnknown,DataSrc2));
//如果成功(DataSrc1.QueryInterface(IID_IDBProperties,Properties1))和
Succeeded(DataSrc2.QueryInterface(IID_IDBProperties,Properties2))然后$ b,则查询数据源对象
的IDBProperties对象$ b begin
//获取数据源对象的属性
OleCheck(Properties1.GetProperties(0,nil,PropSetCnt1,PropSet1));
OleCheck(Properties2.GetProperties(0,nil,PropSetCnt2,PropSet2));
try
//同一数据库提供者将具有相同的初始化属性集,
//因此,第一个检查可能是属性计数,如果不同,则
//至少DB提供者是不同的,所以如果相等,则...
如果PropSetCnt1 = PropSetCnt2然后
开始
//初始化正结果
结果:= True;
//将I的所有属性
迭代到PropSet1.cProperties-1做
开始
//检查我们是否在比较相同的属性,如果是,比较
//属性值;对于密码属性,将值与大小写
//敏感度进行比较,对于其他所有情况则不区分大小写;如果此
//中的任何一个都不匹配,则结果为False,并且如果(PropSet1.rgProperties [I] .dwPropertyID<>
PropSet2,则可以退出
。 rgProperties [I] .dwPropertyID)或
不是IsSameVarWideStr(PropSet1.rgProperties [I] .vValue,
PropSet2.rgProperties [I] .vValue,
PropSet1.rgProperties [I] .dwPropertyID = DBPROP_AUTH_PASSWORD)然后
开始
结果:= False;
休息时间;
结尾;
结尾;
结尾;
最终
//释放属性集;请注意,您应该避免使用该常见的
// try..finally块,并且还应该使用IMalloc :: Free释放每个属性数组
//元素。为什么我使用了CoTaskMemFree,请参阅此
//问题http://stackoverflow.com/q/3079508/960757
CoTaskMemFree(PropSet1);
CoTaskMemFree(PropSet2);
结尾;
结尾;
结尾;
结尾;

我认为用法很清楚,所以我宁愿提及一些连接字符串的结果:

  IsSameConnStr = True 
AConnStr1:Provider = MSDASQL.1;持久安全信息= True;数据源=数据源
AConnStr2:提供程序= MSDASQL.1;持久安全信息=正确;数据源=数据源

IsSameConnStr =真
AConnStr1:提供程序= MSDASQL.1;数据源=数据源;持久性安全信息= True
AConnStr2:提供程序= MSDASQL.1;持久安全信息= True;数据源= DATASOURCE

IsSameConnStr = True
AConnStr1:提供程序= MSDASQL.1;密码= PASSWORD ;数据源=数据源;持久性安全信息=真
AConnStr2:提供程序= MSDASQL.1;数据源= DATASOURCE;密码= PASSWORD;持久性安全信息=真

IsSameConnStr = False-密码区分大小写
AConnStr1:提供程序= MSDASQL.1;密码= PASSWORd;数据源=数据源;持久安全信息=真实
AConnStr2:提供程序= MSDASQL.1;数据源e = DATASOURCE;密码= PASSWORD;持久安全信息=真实


I need to be able to compare two different connection strings together and identify whether or not they are the same info. I cannot do a simple string comparison, because the properties could be laid out differently, but still represent the same connection.

Before I go and write my own comparison for this, is there already something that can do this?

I've searched for a way and I can't find anything out there about this.

解决方案

You might use the IDataInitialize::GetDataSource method, which returns an uninitialized data source object from a given connection string. Because of this method returns pointer to a data source object of a IUnknown type, you cannot directly compare the objects obtained for your two compared connection strings. However, you can query the IDBProperties interface on those uninitialized data source objects what gives you a possibility to access all properties supported by a given provider.

To get a property set, you need to use IDBProperties::GetProperties method. This will return a DBPROPSET structure, which contains an array of DBPROP elements (properties). You will then simply iterate this array and compare the properties of those two data source objects in a way you need.

The following IsSameConnStr function returns True if the connection strings equal, False otherwise. Note, that the used property value comparison is case insensitive except the DBPROP_AUTH_PASSWORD property, which is compared with case sensitivity:

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;

The usage is clear I think, so I'll rather mention results for some connection strings:

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

这篇关于有什么简单的方法可以比较连接字符串而不自己解析吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆