Delphi5でZeosLibを使用してMySQL(UTF8)にアクセスする
ネットで情報が皆無に等しかったので書いてみました。(Lazarusの記事は少しある。)
これができればDelphi5(1999年)でも2020年ぐらい迄、使えそうです@@;
目的
・BDE(Borland Database Engine)を使用しないでデータベースを扱う。
・データベースの文字コードはDelphi5で対応していないUTF8を扱う。
目的を達成するには・・・
・無料のZeosLibを使用してネイティブで高速にデータベースを扱う。
開発環境
・WindowsXp(32bit)/Windows7(64bit)
・Delphi5(Professional)
・MySQL5.5(32bit/ローカル/UTF8)
・libmysql.dll(ネイティブ用)
・ZeosLib6.6.6
※ZeosLibのバージョンを下げればDelphi4なども動きます。
※Personal版は持っていないので分かりません。
以下からインストールなどの作業となります。
1.ZeosLibをダウンロードする
公式サイト:http://zeoslib.sourceforge.net/portal.php
sourceforge:http://sourceforge.net/projects/zeoslib/
今回はDelphi5で使用する為に「ZEOSDBO-6.6.6-stable.zip」をダウンロードします。
URL:http://sourceforge.net/projects/zeoslib/files/Zeos%20Database%20Objects/zeosdbo-6.6.6-stable/
2.libmysql.dllをダウンロードする
http://dev.mysql.com/downloads/connector/c/からZIP Archiveをダウンロードします。
ダウンロードを押したらページ下部の「No thanks, just start my download.」をクリックしてください。
その次にbinまたはlibフォルダにある「libmySQL.dll」を取得して、名前を「libmysqld51.dll」に変更してください。
変更したDLLはDelphiで作成する実行ファイル(EXE)と同一のフォルダ内かシステムフォルダ?に置いてください。
3.DelphiにZeosLibをインストールする
1.ツール→環境オプションでライブラリパスにパスを追加する。

※本当はもっとスマートに出来ると思います。10年ぐらいぶりにDelphiを触ったもので・・・。
2.Delphiから以下のファイルを開き「コンパイル」する。
・ZEOSDBO-6.6.6-stable\packages\delphi5\ZCore.dpk
・ZEOSDBO-6.6.6-stable\packages\delphi5\ZPlain.dpk
・ZEOSDBO-6.6.6-stable\packages\delphi5\ZParseSql.dpk
・ZEOSDBO-6.6.6-stable\packages\delphi5\ZDbc.dpk
3.次は以下のファイルを開き「インストール」する。
ZEOSDBO-6.6.6-stable\packages\delphi5\ZComponent.dpk
※Professional版だと「vcl50ado」辺りがエラーになると思いますので、それはコメントにして下さい。
インストールするとこんな感じになります。

4.DelphiでZeosLibを使用する。
TZConnection/TZReadOnlyQueryを設置する。

いきなりソース書きます@@;
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ZConnection, Db, ZAbstractRODataset, ZDataset;
type
TForm1 = class(TForm)
ZReadOnlyQuery1: TZReadOnlyQuery;
ZConnection1: TZConnection;
Button1: TButton;
Memo1: TMemo;
procedure ZReadOnlyQuery1AfterOpen(DataSet: TDataSet);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
// UTF8→SJIS変換
function Utf8NToSjis(const s: string): string;
var
Len: integer;
OutPwc: PWideChar;
SIn: string;
begin
Result := '';
SIn := S + #0#0;
Len := MultiByteToWideChar(CP_UTF8, 0, PChar(SIn), Length(SIn), nil, 0);
if Len = 0 then
raise Exception.Create('指定のUTF8文字列の変換は出来ません.');
OutPwc := AllocMem(Len * 2);
try
MultiByteToWideChar(CP_UTF8, 0, PChar(SIn), Length(SIn), OutPwc, Len);
WideCharToStrVar(OutPwc, Result);
finally
FreeMem(OutPwc);
end;
end;
procedure TForm1.ZReadOnlyQuery1AfterOpen(DataSet: TDataSet);
var
Field : TField;
S : string;
begin
Field := DataSet.FindField('old_text') ;
if Field.IsNull then
begin
// データがないよ
Exit;
end;
// Memoへ表示(utf8からsjisへ変換)
memo1.text := Utf8NToSjis(Field.AsString);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
// 自動コミットなし
ZConnection1.AutoCommit :=false;
// ホスト名(ローカルならlocalhost ※MySQLの設定による)
ZConnection1.HostName :='192.168.1.x'; //
// DB名
ZConnection1.Database :='データベース名';
// ユーザー名
ZConnection1.User :='ユーザー名';
// パスワード
ZConnection1.Password :='パスワード' ;
// プロトコル
ZConnection1.Protocol :='mysqld-5';
// 読み込み専用
ZConnection1.ReadOnly := true;
// DB接続
ZConnection1.connected :=true ;
// クエリー設定
ZReadOnlyQuery1.Connection := ZConnection1;
// 文字コードをUTF8に設定する(必須)
ZReadOnlyQuery1.SQL.Text := 'SET CHARACTER SET utf8';
ZReadOnlyQuery1.ExecSQL;
ZReadOnlyQuery1.SQL.Text :='';
// SQLの実行
ZReadOnlyQuery1.SQL.Text := '';
ZReadOnlyQuery1.SQL.add('SELECT old_text FROM text where old_id =50467911');
ZReadOnlyQuery1.Open;
// DB接続解除
ZConnection1.Connected := false;
end;
end.
※Utf8NToSjisはDelphi掲示板から引用しました。
※日本語を含むSQLは文字コードをUTF8に変換してからSQLを投げて下さい。
実行すると下記のようになります。(wikipediaのローカルデータベースから織田信長のデータ抽出)

5.実は... ZeosLib6.6.6は「いにしえ」のバージョンなのでメモリリークがあり修正が必要です^^;
このままの状態ですとデータベースに接続して解放をするだけで以下のようになります@@;

※メモリリークチェッカーは「MemCheck2.0」を使用しています。
メモリリークの箇所は「ZPlainMySqlDriver.pas」にあります。
// 呼び出し箇所
procedure TZMySQLD5PlainDriver.BuildArguments(Options: TStrings);
begin
BuildServerArguments(Options);
end;
// メモリリーク箇所
implementation
uses SysUtils;
var
ServerArgs: array of PChar; // なんとここにポインタ配列が@@;
ServerArgsLen: Integer;
procedure BuildServerArguments(Options: TStrings);
var
TmpList: TStringList;
i: Integer;
begin
TmpList := TStringList.Create;
try
TmpList.Add(ParamStr(0));
for i := 0 to Options.Count - 1 do
if SameText(SERVER_ARGUMENTS_KEY_PREFIX,
Copy(Options.Names[i], 1,
Length(SERVER_ARGUMENTS_KEY_PREFIX))) then
{$IFDEF VER140BELOW}
TmpList.Add(Options.Values[Options.Names[i]]);
{$ELSE}
TmpList.Add(Options.ValueFromIndex[i]);
{$ENDIF}
//Check if DataDir is specified, if not, then add it to the Arguments List
If TmpList.Values['--datadir'] = '' then
TmpList.Add('--datadir='+EMBEDDED_DEFAULT_DATA_DIR);
ServerArgsLen := TmpList.Count;
SetLength(ServerArgs, ServerArgsLen);
for i := 0 to ServerArgsLen - 1 do
ServerArgs[i] := StrNew(PChar(TmpList[i])); // ここで領域を確保しているが解放していない
finally
TmpList.Free;
end;
end;
以下は、修正後の状態です。
TZMySQLD5PlainDriver = class (TZMySQL5PlainDriver)
public
destructor Destroy; override; // ここにデストラクタを追加
function GetProtocol: string; override;
function GetDescription: string; override;
procedure Initialize; override;
function Init(var Handle: PZMySQLConnect): PZMySQLConnect; override;
procedure BuildArguments(Options: TStrings); override;
end;
{ TZMySQLD5PlainDriver }
// デストラクタを追加
destructor TZMySQLD5PlainDriver.Destroy;
var
i : Integer;
begin
for i := 0 to ServerArgsLen - 1 do
StrDispose(ServerArgs[i]);
inherited;
end;
procedure BuildServerArguments(Options: TStrings);
var
TmpList: TStringList;
i: Integer;
begin
TmpList := TStringList.Create;
try
TmpList.Add(ParamStr(0));
for i := 0 to Options.Count - 1 do
if SameText(SERVER_ARGUMENTS_KEY_PREFIX,
Copy(Options.Names[i], 1,
Length(SERVER_ARGUMENTS_KEY_PREFIX))) then
{$IFDEF VER140BELOW}
TmpList.Add(Options.Values[Options.Names[i]]);
{$ELSE}
TmpList.Add(Options.ValueFromIndex[i]);
{$ENDIF}
//Check if DataDir is specified, if not, then add it to the Arguments List
If TmpList.Values['--datadir'] = '' then
TmpList.Add('--datadir='+EMBEDDED_DEFAULT_DATA_DIR);
// ここに解放処理を追加
if (ServerArgsLen<>-1) then
for i := 0 to ServerArgsLen - 1 do
StrDispose(ServerArgs[i]);
ServerArgsLen := TmpList.Count;
SetLength(ServerArgs, ServerArgsLen);
for i := 0 to ServerArgsLen - 1 do
ServerArgs[i] := StrNew(PChar(TmpList[i]));
finally
TmpList.Free;
end;
end;
※慣れた方がやればもっとスマートに修正できると思います^^;
※ここで修正したのはMySQL5の場合のみです。その他のバージョンやデータベースを使う場合は適宜、バグがあるか確認してから修正して下さい。
6.完了です^^
このきじをかいたのは「papy」です。おやくにたてればさいわいです。
広告
前の画面に戻る