為支援Unicode準備-VCL和dbExpress

BDS 2006的功能文件中著明瞭dbExpressMS SQL Server驅動程式支援MS SQL 2005以及Unicode,這非常的有趣。為什麼? 因為這牽涉到了許多的事情。首先許多Delphi/C++Builder的使用者早已要求Borland推出支援UnicodeVCL架框,這個支援UnicodeVCL架框早在Delphi 2時我便向Delphi R&D團隊要求,因為當時我在臺灣負責和新加坡同事為Delphi開發中文套件就我就覺得有這個需要。而當時Anders也認為這很重要,也準備為VCL架框加入Unicode的能力,可惜的是人去樓空,隨著Anders的離開這個功能也就一直被懸而未決。

 

隨著多語言環境不斷的成長和成熟,UnicodeVCL架框似乎再也不能拖了,因此Borland2005DelphiRoadmap上宣示了在Delphi 64位元的版本中,VCL架框將支援Unicode。那麼對於目前需要UnicodeDelphi/C++Builder開發人員要怎麼辦呢? 就我所知,許多人目前都是使用TNT控制項來解決這個需求:

 

http://www.tntware.com/delphicontrols/unicode/

 

即然VCL架框在未來才準備支援Unicode,而BDS 2006MS SQL Server dbExpress驅動程式已經支援了Unicode,那麼這是怎麼做到的? 其實Borland雖然在未來才準備讓VCL架框支援Unicode,但是在BDS 2006VCL架框中卻已經開始了這個工作,修改了許多VCL的方法,特性,事件和類別,介面等。也加入了一些新的類別,如此一來才能讓dbExpress驅動程式和VCL架框配合。例如在BDS 2006VCL架框中,和dbExpress相關的TCustomSQLDataSet類別已經改成是從TWideDataSet繼承下來,而不再是像Delphi 2005和以前的版本,是直接從TDataSet繼承下來。

  TCustomSQLDataSet = class(TWideDataSet)

  Private

   

 

TWideDataset是一個新加入的類別,仔細看看TWideDataSet類別,主要是加入了WideString的支援宣告,為Unicode做準備,此外TWideDataset也複載了許多支援WideString的方法,為執行包含UnicodeSQL敘述和命令做準備。

{ TWideDataset }

 

  TWideDataSet = class(TDataSet, IProviderSupport2)

  protected

    function PSExecuteStatement(const ASQL: string; AParams: TParams;

      ResultSet: Pointer = nil): Integer; overload; override; deprecated;

    function PSExecuteStatement(const ASQL: WideString; AParams: TParams;

      ResultSet: Pointer = nil): Integer; overload; override;

    function PSGetCommandText: string; override; deprecated;

    function PSGetCommandTextW: WideString; override;

    function PSGetKeyFields: string; override; deprecated;

    function PSGetKeyFieldsW: WideString; override;

    function PSGetQuoteChar: string; override; deprecated;

    function PSGetQuoteCharW: WideString; override;

    function PSGetTableName: string; override; deprecated;

    function PSGetTableNameW: WideString; override;

    procedure PSSetCommandText(const CommandText: string); overload; override; deprecated;

    procedure PSSetCommandText(const CommandText: WideString); overload; override;

    function IProviderSupport2.PSGetCommandText = PSGetCommandTextW;

    function IProviderSupport2.PSGetKeyFields = PSGetKeyFieldsW;

    function IProviderSupport2.PSGetQuoteChar = PSGetQuoteCharW;

    function IProviderSupport2.PSGetTableName = PSGetTableNameW;

  end;

 

除此之外,對於dbExpress來說,BDS 2006也加入了一些新的wrapper類別來封裝dbExpress的介面,例如對於dbExpressISQLMetaData介面,Delphi 2005加入了TISQLMetaData25封裝類別,BDS 2006則加入了TISQLMetaData30封裝類別。TISQLMetaData25封裝類別複載了抽象虛擬類別 : TISQLMetaData抽象虛擬類別,並且使用做為實作的介面。

  TISQLMetaData25 = class(TISQLMetaData)

  protected

    I : ISQLMetaData25;

  public

    constructor Create(newMetaData: ISQLMetaData25);

    destructor Destroy; override;

    function SetOption(eDOption: TSQLMetaDataOption;

                     PropValue: LongInt): SQLResult; override;

    function SetStringOption(eDOption: TSQLMetaDataOption;

                     const str: WideString): SQLResult; override;

    function GetOption(eDOption: TSQLMetaDataOption; PropValue: Pointer;

                     MaxLength: SmallInt; out Length: SmallInt): SQLResult; override;

    function GetStringOption(eDOption: TSQLMetaDataOption;

                     var str: WideString): SQLResult; override;

    function getObjectList(eObjType: TSQLObjectType; var Cursor: TISQLCursor):

                     SQLResult; override;

    function getTables(TableName: PWideChar; TableType: LongWord;

                     var Cursor: TISQLCursor): SQLResult; override;

    function getProcedures(ProcedureName: PWideChar; ProcType: LongWord;

                     var Cursor: TISQLCursor): SQLResult; override;

    function getColumns(TableName: PWideChar; ColumnName: PWideChar;

                     ColType: LongWord; var Cursor: TISQLCursor): SQLResult; override;

    function getProcedureParams(ProcName: PWideChar; ParamName: PWideChar;

                     var Cursor: TISQLCursor): SQLResult; override;

    function getIndices(TableName: PWideChar; IndexType: LongWord;

                     var Cursor: TISQLCursor): SQLResult; override;

    function getErrorMessage(Error: PWideChar): SQLResult; overload; override;

    function getErrorMessageLen(out ErrorLen: SmallInt): SQLResult; override;

    function getErrorMessage(var Error: WideString): SQLResult; overload; override;

  end;

 

TISQLMetaData30也是複載了抽象虛擬類別 : TISQLMetaData抽象虛擬類別,但是使用了ISQLMetaData30介面做為實作的依據。

  TISQLMetaData30 = class(TISQLMetaData)

  protected

    I : ISQLMetaData30;

  public

    constructor Create(newMetaData: ISQLMetaData30);

    destructor Destroy; override;

    function SetOption(eDOption: TSQLMetaDataOption;

                     PropValue: LongInt): SQLResult; override;

    function SetStringOption(eDOption: TSQLMetaDataOption;

                     const str: WideString): SQLResult; override;

    function GetOption(eDOption: TSQLMetaDataOption; PropValue: Pointer;

                     MaxLength: SmallInt; out Length: SmallInt): SQLResult; override;

    function GetStringOption(eDOption: TSQLMetaDataOption;

                     var str: WideString): SQLResult; override;

    function getObjectList(eObjType: TSQLObjectType; var Cursor: TISQLCursor):

                     SQLResult; override;

    function getTables(TableName: PWideChar; TableType: LongWord;

                     var Cursor: TISQLCursor): SQLResult; override;

    function getProcedures(ProcedureName: PWideChar; ProcType: LongWord;

                     var Cursor: TISQLCursor): SQLResult; override;

    function getColumns(TableName: PWideChar; ColumnName: PWideChar;

                     ColType: LongWord; var Cursor: TISQLCursor): SQLResult; override;

    function getProcedureParams(ProcName: PWideChar; ParamName: PWideChar;

                     var Cursor: TISQLCursor): SQLResult; override;

    function getIndices(TableName: PWideChar; IndexType: LongWord;

                     var Cursor: TISQLCursor): SQLResult; override;

    function getErrorMessage(Error: PWideChar): SQLResult; overload; override;

    function getErrorMessageLen(out ErrorLen: SmallInt): SQLResult; override;

    function getErrorMessage(var Error: WideString): SQLResult; overload; override;

  end;

 

那麼ISQLMetaData25ISQLMetaData30有什麼不同? 細節看看下面這兩個介面的差異:

ISQLMetaData25 = interface(ISQLMetaData)

   function SetOption(eDOption: TSQLMetaDataOption;

                     PropValue: LongInt): SQLResult; stdcall;

   function GetOption(eDOption: TSQLMetaDataOption; PropValue: Pointer;

                     MaxLength: SmallInt; out Length: SmallInt): SQLResult; stdcall;

   function getObjectList(eObjType: TSQLObjectType; out Cursor: ISQLCursor25):

                     SQLResult; stdcall;

   function getTables(TableName: PChar; TableType: LongWord;

                     out Cursor: ISQLCursor25): SQLResult; stdcall;

   function getProcedures(ProcedureName: PChar; ProcType: LongWord;

                     out Cursor: ISQLCursor25): SQLResult; stdcall;

   function getColumns(TableName: PChar; ColumnName: PChar;

                     ColType: LongWord; Out Cursor: ISQLCursor25): SQLResult; stdcall;

   function getProcedureParams(ProcName: PChar; ParamName: PChar;

                     out Cursor: ISQLCursor25): SQLResult; stdcall;

   function getIndices(TableName: PChar; IndexType: LongWord;

                     out Cursor: ISQLCursor25): SQLResult; stdcall;

   function getErrorMessage(Error: PChar): SQLResult; overload; stdcall;

   function getErrorMessageLen(out ErrorLen: SmallInt): SQLResult; stdcall;

end;

 

我們可以清楚的看到ISQLMetaData25ISQLMetaData30介面不同的地方是ISQLMetaData30完全使用WideString的格式來處理後理後端的資料來源,而ISQLMetaData25則是使用一般的字串格式,這代表ISQLMetaData30介面能夠處理Unicode的資料。當然,BDS 2005其他封裝dbExpress介面的wrapper類別也是類似的。

ISQLMetaData30 = interface(ISQLMetaData)

   function SetOption(eDOption: TSQLMetaDataOption;

                     PropValue: LongInt): SQLResult; stdcall;

   function GetOption(eDOption: TSQLMetaDataOption; PropValue: Pointer;

                     MaxLength: SmallInt; out Length: SmallInt): SQLResult; stdcall;

   function getObjectList(eObjType: TSQLObjectType; out Cursor: ISQLCursor30):

                     SQLResult; stdcall;

   function getTables(TableName: PWideChar; TableType: LongWord;

                     out Cursor: ISQLCursor30): SQLResult; stdcall;

   function getProcedures(ProcedureName: PWideChar; ProcType: LongWord;

                     out Cursor: ISQLCursor30): SQLResult; stdcall;

   function getColumns(TableName: PWideChar; ColumnName: PWideChar;

                     ColType: LongWord; Out Cursor: ISQLCursor30): SQLResult; stdcall;

   function getProcedureParams(ProcName: PWideChar; ParamName: PWideChar;

                     out Cursor: ISQLCursor30): SQLResult; stdcall;

   function getIndices(TableName: PWideChar; IndexType: LongWord;

                     out Cursor: ISQLCursor30): SQLResult; stdcall;

   function getErrorMessage(Error: PWideChar): SQLResult; overload; stdcall;

   function getErrorMessageLen(out ErrorLen: SmallInt): SQLResult; stdcall;

end;

 

現在封裝dbExpressVCL類別都已經完成了對於Unicode的支援,就等Borland推出支援各種關連資料庫的dbExpress驅動程式即可。而VCL架框也在穩定的朝向支援Unicode的方向前進,依照DelphiRoadmap,我們將可望在Borland推出代號為HighLanderBDS之後,看到全新架構的VCL架框。

 

在此時和dbExpress 3.0玩玩真的很有意思, dbExpress 3.0不但功能更多了, 效率也比以前的dbExpress快上了許多, 可以說是目前Win32下最好的資料存取技術了.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章