PDF版をダウンロードする

Yet another Open Source Database
Firebird RDBMS
傾向と対策 1
林 務(株式会社アペックス)
mail:[email protected]
はじめに
本書は、PS ネットワークより平成 15 年 3 月 3 日に初版が出版された『Pocket Tech Note Firebird RDBMS 傾向と対策 1』の原稿を基
にして PDF 化したものです。出版の際には B6 サイズの横長の体裁でしたが、PDF 化するにあたって、A4 縦のサイズへと変更し、必要最
低限の編集を加えています。昨年 PDF 化して公開した『Pocket Tech Note Firebird RDBMS 傾向と対策 2』に引き続き、公開をするこ
ととなりました。本書刊行時には末尾に Ann Harison 著の『How InterBase came to be – InterBase はどのようにして生まれたか - 』
と『Interbase With a Small 'b' Harrison のはるかな回想』
、また Jim Starkey による『Jim Starkey による回想』の翻訳を収録して
いましたが、こちらは Firebird 日本ユーザー会のサイト(http://www.firebird.gr.jp/)にて別途公開しているため、PDF 版への収録は
見送りました。
本書の内容は、Firebird の 1.0.2 がリリースされた当初のものですが、基本的な SQL の構文やデータ型に関する知識は、いまでも大
きく変わっていません。管理ツールとしてご紹介した IBOConsole や Marathon はその後開発が中断しており、現在では Firebird Project
公式の管理ツールとして FlabeRobin が開発・公開されています。
Firebird 日本ユーザー会の加藤大受氏が日本語を行っており、Firebird
日本ユーザー会のページからもダウンロードすることが出来ますので、今後はこちらをお使い下さい。
2007 年 11 月に版元であった PS ネットワークの武田浩一氏が若くして急逝され、PS ネットワークが廃業となったため、多少でも
Firebird の普及のお役に立てればとの想いから、
ここに執筆者としての責任においてこれを PDF 化してお配りすることにいたしました。
Delphi マガジンや nifty serve の FDELPHI でご活躍された武田浩一さんが、Firebird の普及にも尽力されていたことに感謝するととも
に、ご冥福をお祈り申し上げます。
(2009 年 11 月 25 日ウルトラの街にて 林 務)
まえがき
2000 年 7 月 25 日に Borland 社の RDBMS、InterBase のソースコードが公開されて以来、
すでに 2 年以上が経過しました。
この間、
Borland
社は InterBase に関する政策を一転し、バージョン 6、6.5 は従来どおりの商用ライセンスに基づいて販売されています。そして、公開
されたソースコードに関して Borland 社は、現在では一切の更新を行っていません。
しかし、オープンソースとなった InterBase のソースコードから、不死鳥のごとく Firebird が生まれ、いまなお成長を続けています。
2002 年 12 月には、初のメンテナンス・リリースとなるバージョン 1.0.2 がリリースされ、着実に地歩を固めつつあります。本書の目
的は、このオープンソースの RDBMS、Firebird を紹介することにあります。
本書は、Delphi マガジン Vol.26 に掲載された原稿を元に大幅に加筆・修正をしたものです。本書では、RDBMS や SQL とは何かといっ
た初歩的な話題については扱っておりませんので、それらについての基礎的な知識については別途書籍や雑誌を参考にしてください。
前半では Firebird の概要と独自の拡張などに付いて説明し、インストールと基本的な管理の方法を解説しています。InterBase と共
にソースコードが公開された IBConsole は開発チームが Firebird プロジェクトと敵対してしまっているようなので、IBOConsole と
Marathon というオープンソースの管理コンソールを使った利用方法を採用しました。
後半では、Firebird を Delphi + dbExpress で使用した見積書アプリケーションの作成を通して、クライアントデータセットの利用
法、ストアドプロシージャーの利用法など、総合的なアプリケーション作成技法を示しました。筆者の技量が足りない面も多々ありま
すが、読者の皆さまの一助になれば幸いです。
末筆ながら、Firebird の開発を献身的に行っているプロジェクトの皆さんに感謝いたします。とりわけ、IBPhenix 社の Ann Harrison
さんには、Firebird の歴史を翻訳して公開する件を快く認めていただき、ありがとうございました。感謝いたします。
また、本書を執筆する機会を与えてくださった PS ネットワークの武田さん、エア・ロジックの近藤さんに感謝いたします。そして、
私が Delphi プログラマの端くれとして存在する前提となった、@nifty FDELPHI のみなさんに感謝いたします。
なによりも、病の中で苦しみながらも協力してくれた愛する妻に感謝します。
目次
はじめに ...................................................................................................... 1
まえがき ...................................................................................................... 1
Yet another Open Source Database ............................................................................... 1
FIREBIRD RDBMS 傾向と対策 1 ..................................................................................... 1
はじめに ...................................................................................................... 4
FIREBIRD の概要 ................................................................................................ 5
FIREBIRD のアーキテクチャー.........................................................................................
FIREBIRD の特徴 ....................................................................................................
アクティブデータベース............................................................................................
計算項目 .......................................................................................................
ユーザー定義関数(UDF) ..........................................................................................
Blob フィルタ ..................................................................................................
外部キーを含む、列及びテーブル制約 .............................................................................
トリガーとビュー・トリガー .....................................................................................
ストアド・プロシージャ- .......................................................................................
ローカライゼーション ...........................................................................................
FIREBIRD 独自の拡張 ................................................................................................
5
5
6
6
6
6
6
6
6
7
7
FIREBIRD のインストール ........................................................................................ 9
WINDOWS へのインストール ........................................................................................... 9
LINUX へのインストール .............................................................................................12
FIREBIRD の管理方法 ........................................................................................... 13
FIREBIRD SERVICE MANAGER .............................................................................................13
コマンドラインツール..............................................................................................14
ISQL の使い方 ..................................................................................................14
IBOCONSOLE ........................................................................................................15
サーバーの登録 .................................................................................................16
ユーザーセキュリティ ...........................................................................................16
サーバーのプロパティ ...........................................................................................17
データベースの登録 .............................................................................................18
データベースのバックアップ・リストア ...........................................................................20
バックアップオプション .........................................................................................20
データベースのリストア .........................................................................................21
リストア・オプション ...........................................................................................21
トム猫の独り言(1) IBCONSOLE と CLASSICSERVER .................................................................... 22
FIREBIRD プログラミング ....................................................................................... 23
見積書データベースの作成 ..........................................................................................23
テーブル構造 ...................................................................................................23
ドメイン定義 ...................................................................................................23
ジェネレーター定義 .............................................................................................24
トリガー定義 ...................................................................................................24
MARATHON...........................................................................................................25
Marathon のインストール .........................................................................................25
Marathon の起動 ................................................................................................25
新規データベースの作成 .........................................................................................26
ドメインの作成 .................................................................................................28
ジェネレーターの作成 ...........................................................................................29
テーブルの作成 .................................................................................................30
トリガーの作成 .................................................................................................32
ストアドプロシージャーの作成 ...................................................................................34
データベースへのデータの挿入 ...................................................................................36
データベースからのデータの表示 .................................................................................37
トム猫の独り言(2) オープンソースとライセンス ................................................................... 40
DELPHI から利用する FIREBIRD ................................................................................... 41
DELPHI データベースプログラミングスキーム ..........................................................................41
...................................................................................................42
見積書アプリケーションの作成 ......................................................................................43
データベース接続の設定 .........................................................................................44
各データセットの設定 ...........................................................................................45
DBEXPRESS の概要
調停ダイアログの追加 ...........................................................................................48
メインフォームの作成 ...........................................................................................49
継承元ベースフォームの作成 .....................................................................................49
Constants.pas と Globals.pas ....................................................................................51
顧客・商品追加フォーム .........................................................................................51
トム猫の独り言(3) OVERRIDE と隠蔽 ..................................................................................51
見積基本情報追加フォーム .......................................................................................53
見積詳細情報の追加フォーム .....................................................................................54
顧客マスタの編集・削除フォーム .................................................................................56
見積基本情報の編集・削除フォーム ...............................................................................57
見積詳細情報の編集・削除 ........................................................................................57
見積書の印刷 ...................................................................................................59
はじめに
筆者は日頃、Delphi を使用してプログラミングを行っています。Professional 版以上の Delphi には InterBase のローカル版が付属
しているため、手軽に本格的なクライアント/サーバー・システムの開発を試みることが出来ます。筆者が Delphi に触れ始めたバージ
ョン 2 の頃は、まだオープンソースの RDBMS など存在しなかったか、あるいは知られていなかった上、商用の RDBMS は大変高価なもの
だったので、InterBase を使うことによってはじめて本格的な RDBMS に触れることができたのです。
その後、InterBase を利用したシステムの開発をお手伝いするようなことも有り、筆者にとっては大変なじみのある RDBMS である
InterBase がオープンソースとなったことは知ってはいたものの、情報も少なくメディアでもほとんど取り上げられてこなかったため、
よく分からない状況が続いていました。オープンソースの RDBMS といえば、PostgreSQL か MySQL という状況があり、筆者もそういうも
のだと思っていました。そんな時、Open Source Database Conference の記事をアスキーLinux マガジンのサイト1で見かけ、InterBase
から生まれた Firebird が着実に成長していることを知りました。
今回こうして、Firebird の紹介をさせたいただけることは、筆者にとっては大きな喜びです。読者の皆さんに、Firebird の素晴らし
さを少しでもお伝えすることが出来れば幸いです。
SourceForge 上の Firebird HP
1
日刊アスキーLinux http://linux.ascii24.com/ トップページから、Firebird で検索すると、他の記事に埋もれるようにしてカンフ
ァレンスの記事が 1 件だけ出てきます。こういう状況なんですね。
Firebird の概要
Firebird は InterBase から生まれました。米国 Inprise 社(当時)が、自社の製品である InterBase のソースコードをオープンソース
としたことにより、コミュニティによって Firebird として開発が進められてきました。Firebird の開発には、InterBase の生みの親で
ある Jim Starkey2氏と Ann Harrison3氏が深く関わっています。その意味では、Firebird こそ「真の」InterBase であるといえるかもし
れません。当然のことながら、Firebird には InterBase との「ほぼ」100%の互換性があります。
Firebird は InterBase Public License v.1.0 の下でリリースされたソースコードに基づいて開発・強化が行われてきました4。現在
も、C で書かれたソースコードを C++に書き換えることを目的とした ver.1.5 の開発と、大幅に機能を強化した ver.2.0 の開発が並行し
て SourceForge.net 上で行われています。
Firebird は ANSI SQL-92 に準拠した、扱いやすく堅固としたリレーショナルデータベースです。Linux、Windows、さらには MacOS X
や FreeBSD、Soralis そして各種の Unix プラットフォーム上で動作します。
Firebird の生みの親の一人であり、現在もコミュニティのリーダーとして開発を進めている、IBPhoenix 社の Ann Harrison 氏によれ
ば、Firebird の競争相手は、Oracle、Microsoft SQL Server、 Informix、Sybase、SQLBase、DB2、Solid、Ingres などの多数の商用 RDBMS
です。オープンソースの RDBMS には、他にも PorsgreSQL や MySQL、HSQL、LEAP、ocelot などがあります。
Firebird のアーキテクチャー
Firebird は高度なトランザクション管理機能を備えたリレーショナルデータベースです。Firebird のトランザクション機能は履歴型
アーキテクチャー(Multi Generation Architecture)によって実現されています。履歴型アーキテクチャーは PostgreSQL でバージョン
6.5 から採用されている MVCC(Multi Version Concurrency Control)と同様の機能で、Firebird の出発点となっているアーキテクチャ
ーでもあるので、PostgreSQL はようやく Firebird に追いついたところと言えるかもしれません。
トランザクションとは、データベースに対する操作を複数(単数でも構いません)まとめて一つの単位として取り扱い、データベー
スの一貫性を保証する機能です。ANSI SQL 標準では、
「READ UNCOMMITTED」、
「READ COMMITTED」、
「REPEATABLE READ」
、および「SERIALIZABLE」
という 4 つのトランザクション分離レベルが定義されています。
Firebird はこのうち、「READ UNCOMMITTED」だけサポートしていません。MS SQL Server や IBM DB2 は 4 つすべてを備えていますが、
Oracle は「READ COMMITTED」と「SERIALIZABLE」しかサポートしていません。Oracle の資料によれば、
「それで十分だから」というこ
とです。実際の運用において、
「READ UNCOMMITTED」を使用する意味があるのは読み取り専用データベースくらいしかありませんので、
理論的には存在していても現実的には意味の無い機能といえるでしょう。
履歴型アーキテクチャーによって、Firebird は高度なトランザクション処理機能を備えています。もっとも高い分離レベルである
「SERIALIZABLE」は、Firebird では「SNAPSHOT」と呼ばれますが、「READ COMMITTED」では避けることの出来ない他のトランザクショ
ンによってコミットされた値の影響を完全に排除することが出来ます。
この場合、通常の行レベルロックでは読み取り中の行は他のトランザクションからは書き込みが行えないようになっています。
Firebird では履歴型アーキテクチャーによって、複数のトランザクションが同一の行に対して読み取りと書き込みを同時に行うことが
出来ます。
また、テーブル全体にロックをかけて読取専用のトランザクションとして利用できる SNAPSHOT TABLE STABILITY という分離レベルも
利用できます。
Firebird の特徴
Ann Harrison 氏の講演「Firebird (yet) another Open Source Database」5によると、Firebird には以下の特徴があります。
・
・
・
・
・
ポータビリティ=幅広いプラットフォームサポート
スモール・フットプリント=サイズが小さいこと
イース・オブ・アドミニストレーション=管理の容易さ
サポート・フォー・スタンダード SQL=標準 SQL への準拠
アクティブ・データベース
ポータビリティについては、上述した通りサポートするプラットフォームが多岐にわたっていますので、Windows から商用 UNIX まで
移行することも容易に出来ます。その際、データベースファイルは、
「そのまま」コピーすれば済んでしまいます。
ファイルサイズ・実行サイズが小さいと言うことは、今日ではそれほど重要視されないかもしれません。しかし、メモリの割り当て
前には約 1MB、割り当てたとしてもそれほどにはならないサイズから、PDA などへの応用が思いつきます。6あるいは、ルーターや情報
家電などその他のインテリジェント機器への組込み Database としても利用可能でしょう。
その場合、管理が容易なことは大いに強みを発揮すると思います。また、専任の DBA を雇えるような企業は中小企業ではまずありま
せんから、そうしたシーンでの利用を想定した場合、Oracle はもちろん、PostgreSQL でも扱いが難しいので、Firebird が強みを発揮
すると思います。
標準 SQL への準拠については、SQL-89 と SQL-92、そして SQL-99 のいくつかについて対応しています。INNER JOIN、LEFT JOIN、RIGHT
JOIN、OUTER JOIN のすべてに対応し、VIEW 内の UNION を含む UNION に対応しています。更新可能な VIEW に対してはダイレクトな更新
が可能で、更新不可能な VIEW に対してトリガーを利用した更新が可能となっています。
SELECT 文のサブクエリーは WHERE 句で使用可能で、IN 表現に対しても使用することが出来ます。残念ながら FROM 句ではサブクエリ
ーを使用できませんが、代わりに複数行を返すストアド・プロシージャーを使用することが出来ます。
2
Jim Starkey 氏は Firebird の顧問会議の一員として IB-Architect メーリングリストに定期的に関わっています。
Ann Harrison 氏は IBPhenix 社の社長であり、Firebird の管理者の一人であり、Firebird の開発者でもあります。
4
InterBase Public Licensev.1.0 は Mozilla Public License v.1.1 の修正版です。
5
IB Phenix 社の HP、General Documentetion に原文があります。 http://www.ibphoenix.com/ を参照。全文の日本語訳が、
http://japan.internet.com/linuxtutorial/20020405/1.html と http://www-1.xdsl.ne.jp/~aj01/rdb/Firebird/ibp_act_db_j.htm
にあります。
6
シャープのザウルスが Linux を搭載して 2002 年 7 月 12 日に発売されています。
3
アクティブデータベース
さて、この中でもアクティブ・データベースは特に重要な概念だと思われます。アクティブ・データベースとは、より多くのプロセ
スをデータベース・サーバー側に実装することによって、ネットワークのトラフィックを抑え、クライアント側の実装を容易にすること
を目的とした機能群によって実現されています7。アクティブ・データベースは、以下の機能によって実現されています。
・
・
・
・
・
・
・
計算項目
ユーザー定義関数(UDF)
Blob フィルタ
外部キーを含む、列及びテーブル制約
トリガーとビュー・トリガー
ストアド・プロシージャ-
ローカライゼーション
計算項目
計算項目は、ある種の VIEW ともいえる機能で、テーブルそのものに式によって計算されたフィールドを作成してしまう機能です。
CREATE TABLE T_Employee
(Emp_no INTEGER NOT NULL,
First_name VARCHAR(10) NOT NULL,
Last_name VARCHAR(10) NOT NULL,
Full_name COMPUTED BY
(Last_name|| ', ' || First_name),
PRIMARY KEY(Emp_no));
この例では、別個に入力された First_name と Last_name を結合して Full_name 列を作成しています。計算項目ではこの他、四則演算
と CAST()関数、UPPER()を関数使用できます。内部関数のうち複数行を対象とした集計関数と、EXTRACT 関数は使用できません。
ユーザー定義関数(UDF)
ユーザー定義関数 UDF は大変パワフルな機能です。Firebird は Delphi、C、C++などのプログラム言語で作成された DLL 等の共有ライ
ブラリを SQL 文中で使用することが出来ます。この機能は、Windows、Linux やその他の UNIX 等の共有ライブラリを使用することの出
来るプラットフォーム上で使用することが出来ます。
InterBase では UDF を利用した列は GROUP BY 句で指定することが出来ませんでした。したがって、他の集計関数と一緒に利用するこ
とが出来ませんでした。Firebird では GROUP BY 句で UDF を利用した列を指定することが出来ます。8
Blob フィルタ
Blob フィルタは特殊な UDF によって、Blob(Binary Large Object)の扱いを拡張するものです。Firebird は標準でテキスト形式の Blob
をサポートしますが、Blob フィルタを使用する事で、Jpeg ファイルを Blob として格納し、BMP として取り出すというようなことが出
来ます。
外部キーを含む、列及びテーブル制約
Firebird は外部キーをサポートしています。また、列及びテーブルに対して Check 句による細かな制約を設定することが可能です。
外部キーのサポートにより、強力な参照整合性制約を設定することが出来ます。また、この外部キーは ON CASCADE 句によって参照元の
データの更新・削除に伴い、参照先のデータの更新・削除を設定することが可能となっています。これは、MS SQL Server ではバージ
ョン 2000 になってから実装された機能です9。
トリガーとビュー・トリガー
トリガーは INSERT・UPDATE・DELETE の各アクションに対して、その前後に特定の操作をさせるものです。Firebird では、単純なビ
ューに対する直接更新が可能ですが、ビュー・トリガーもサポートしているので、より複雑なそのままでは更新不可能なビューに対し
てトリガーを設定することで、更新可能とすることも可能となります。トリガーとストアド・プロシージャ-は標準 SQL を拡張したも
ので、DynamicSQL と呼ばれてい10たようですが、今ではそう言われていないようです。
ストアド・プロシージャ-
トリガーと同様、ストアド・プロシージャ-も他の多くの RDBMS で使用可能な、サーバー側のプログラミング・スキームです。Firebird
は FOR SELECT 文と SUSPEND 文のサポートによって、ストアド・プロシージャーをテーブルのように使用する事が可能となっています。
CREATE PROCEDURE GETEMP ( ROWS INTEGER )
RETURNS (EMP_NO SMALLINT, FIRSTNAME VARCHAR(15), LASTNAME VARCHAR(20))
AS
BEGIN
7
PostgreSQL や Oracle と何か違うの?という問いは、NFS と ActiveDirectory はどこが違うの?という問いと同じかもしれません。
ただし、副作用として内部関数を指定する時に UDF Wrapper という仕掛けが必要となります。この点については、Firebird の開発陣
の中でも意見が割れているようで、UDF Wrapper の詳細も不明です。
9
MS Access では以前からサポートしています。Access2000 で MSDE へのアップサイジング・ウィザードを使用すると、トリガーに置き
換えられます。
10
Linux Magazine 2001 年 1 月号で加藤大受さんが書いていたのですが、その後こうした記述はどこにも見当たりません。(^^?
8
IF (ROWS < 1) THEN EXIT;
FOR SELECT EMP_NO, FIRST_NAME, LAST_NAME FROM EMPLOYEE
ORDER BY LAST_NAME
INTO :EMP_NO, :FIRSTNAME, :LASTNAME
DO
BEGIN
SUSPEND;
ROWS = ROWS - 1;
IF (ROWS < 1) THEN EXIT;
END
END
この例は、サンプルデータベースの Employee.gdb に対して、Last_name での並び順で、指定した行数を返すストアド・プロシージャ
ーです。このストアド・プロシージャーを使用するには以下のようにします。
SELECT * FROM GETEMP(10);
EMP_NO
======
34
105
28
83
109
71
107
29
121
24
FIRSTNAME
================
Janet
Oliver H.
Ann
Dana
Kelly
Jennifer M.
Kevin
Roger
Roberto
Pete
LASTNAME
=====================
Baldwin
Bender
Bennet
Bishop
Brown
Burbank
Cook
De Souza
Ferrari
Fisher
ローカライゼーション
最後にローカライゼーションですが、Firebird はキャラクタセットとコレーションオーダー(照合順序)にかんして、オープンなイン
ターフェースを持っています。これにより、ユーザーは独自のキャラクタセットと照合順序を定義できます。Firebird では 1、2、3 ま
たはそれ以上の長さのバイトで構成されるキャラクタセットを使用する事が出来ます。
キャラクタセットと照合順序はデータベースのデフォルト、データベース接続、テーブルの各列毎に指定することが出来ます。デー
タベースの作成時にデフォルトキャラクタセットを指定しないと NONE キャラクタセットが指定されます。この場合格納されたデータは
キャラクタセット間でのコード変換などに対応できなくなるので、必ず指定するようしましょう。11
Firebird 独自の拡張
さらに、InterBase と比較して Firebird では独自にいくつかの拡張がなされています。
・
・
・
・
・
・
・
・
・
CURREN_USER と CURRENT_ROLE の 2 つのコンテキスト変数の追加
DROP GENERATOR 文の追加
GROUP BY 可能な UDF
RECREATE PROCEDURE/TABLE 文の追加
SELECT FIRST m SKIP n 文の追加
内部関数 SUBSTRING の追加
大文字小文字を区別しないハンガリー語のコレーション追加
チェコ語のキャラクターセット追加
--ではじまる新しいコメント文の追加
他にも InterBase から受け継いだ、イベントアラータやジェネレーター、多次元配列項目など様々な特徴があります。多次元配列に
ついては、注意が必要です。現在のところ、配列として定義された列に Delphi から BDE や dbExpress はもちろん、IBX を通してもアク
セスすることが出来ません。API からアクセスするか、ストアド・プロシージャーで配列を展開してしまわないと利用できないようで
す。
Firebird 独自の拡張になりますが、InterBase ではユーザー定義関数(UDF)で指定された列は GROUP BY 句に指定することが出来ま
せんでした12。Firebird では、これを指定することが可能となっています。その副次的な作用として、これまで不可能だった GROUP BY
句の中での組み込み関数の使用が UDF ラッパー13を使うことで可能となっています。
また、SELECT 文で FIRST・SKIP 句が追加されたことで、PostgreSQL の独壇場であった、LIMIT・OFFSET 句による Web システム向けの
検索が容易になりました。
PostgreSQL で以下のように記述する SELECT 文は、Firebird で次のように記述できます。
11
Windows なら SJIS_0208、Linux なら EUCJ_0208 を無指定の時のデフォルトにしたいですね。
ORDER BY はもともと指定できましたが、列名でなく 1,2,3 などの列番号で指定します。
13
ただし、この機能については Firebird の ML でも問題となっていて、大変わかりづらく使いにくいものになっているようです。筆者
も理解していません。
12
<PostgreSQL>
SELECT * FROM MYTABLE LIMIT 10 OFFSET 10
<Firebird>
SELECT FIRST 10 SKIP 9 * FROM MYTABLE
.....
PostgreSQL の OFFSET 句との違いに注意してください。PostgreSQL は OFFSET で指定したその行から LIMIT 句で指定した行数を返しま
.....
す。Firebird は SKIP 句で指定した行の次の行から FIRST 句で指定した行数を返します。
Firebird のインストール
Firebird のインストールに必要なファイルは以下の URL から入手してください。
SourceForge.net の Firebird プロジェクトホームページ http://Firebird.sourceforge.net/
トップページの Download からリンクをたどってください。Firebird 1.0.2-Release が最新の安定版です。
Windows へのインストール
Windows 版のインストールファイルは次の通りです。
Firebird-1.0.2.908-Win32.exe
起動すると通常のインストーラーが起動しますので、指示に従ってインストールしてください。気をつける点は、以前のバージョン
をアンインストールしてからインストールすることです。インストール中に、いくつか設問がありますが、基本的にデフォルトのまま
で良いでしょう。
①インストールの確認:
「はい」を選択
②インストールバージョンの確認:「Next」を選択
③ライセンスへの同意:
「Yes」を選択
④リリースノート:「Next」を選択
⑤インストールフォルダの選択:「Next」を選択
⑥インストールタイプの選択:
1)サーバーを含んだフルインストール
2)開発用のクライアントツール
3)最小限のクライアント
デフォルトでよいので、
「Next」を選択
⑦スタートメニューへの登録位置:「Next」を選択
⑧オプションの選択:デフォルトでよいので「Next」を選択
⑨インストール準備の完了:「Install」を選択
⑩インストール中画面
⑪インストール情報:「Next」を選択
⑫インストール完了画面:「Finish」を選択
Linux へのインストール
Firebird は Windows 以外ににも、MacOS X 版、HP-UX 版、Solaris 版、FreeBSD 版、Linux 版が利用可能です。ここでは、Linux 版の
インストールについて述べることにします。14
しかし、Linux 版はインストールファイルが多岐にわたっています。筆者は SuperServer 版をインストールしてみました。他に、
ClassicServer 版も用意されています。さらに 32bitI/O と 64bitI/O の別、tar と rpm が選べるので合計 8 つのインストールタイプがあ
ることになります。
ClassicServer と SuperServer の違いは、前者がプロセスモデルで、後者がスレッドモデルで構成されているというだけで、RDBMS と
しての機能に違いはありません。外部からは基本的に全く同じに見えます。
ただし、
ClassicServer には SuperServer にあるサービス API が実装されておらず、
InterBase の付属管理コンソールである IBConsole
から管理が出来ないと言う問題があります。本書では、後述しますが IBConsole のクローンである IBOConsole を使ってサーバーを管理
する方法をご紹介しますので、ClassicServer 版は使用しないことにします。
その他にも、性能上の問題が存在します。プロセス起動方式の方がメモリや CPU により負荷をかけるという問題があるので、
SuperServer の方が性能が上がると言うメリットがあります。Firebird プロジェクトでも、スレッドの実装されていないシステムのた
めに ClassicServer が残されているので、SuperServer 版が将来を担っていくことになると述べられています。
図 1 ClassicServer
図 2 SuperSerber
Linux でスレッドの実装が安定していないので ClassicServer を使用したほうがよいという話も以前はあったようですが、ここでは
32bitI/O 対応の SuperServer 版をインストールすることにします。
インストールファイルは次のようになります。
FirebirdSS-1.0.2.908-0.tar.gz
FirebirdSS-1.0.2.908-0.i386.rpm
両方ともインストールは簡単です。Tar ボールも通常の./configure してから、make するタイプではなく、コンパイル済みのバイナ
リをシェルスクリプトで配置するだけのものです。RPM 版のインストールは以下のコマンドで行います。
#rpm –Uvh FirebirdSS-1.0.2.908-0.i386.rpm
上記のコマンドを実行して何もエラーが出なければインストールは完了です。しかし、筆者が使用している TurboLinux7Workstation
では次のようなエラーが出てしまいます。
Starting Firebird server: root nice: invalid priority `--user'
Firebird サーバーを開始できないようです。調べたところ、/etc/rc.d/init.d にある Firebird スクリプトを書き換えないといけない
ようです。Firebird プロジェクトの方では RedHat で動作確認をしているので、やはり多少の違いがあるようです。下記を参考にして書
き換えてください。
14
単に筆者が他の OS を使っていないだけです。
/etc/rc.d/init.d/Firebird スクリプトの一部
start)
echo -n "Starting Firebird server: "
#
#
daemon --user $FBRunUser $INTERBASE/bin/ibguard -forever
daemon --user $FBRunUser $INTERBASE/bin/ibmgr -start –forever
↑この行を以下のように書き換える
daemon –0 $INTERBASE/bin/ibmgr -start –forever
echo '$INTERBASE/bin/ibmgr -start -forever' | su $FBRunUser
RETVAL=$?
;;
RPM の場合、アンインストールするのも簡単です。次の 1 行で OK です。
#rpm --erase FirebirdSS-1.0.2.908-0
つづいて、tar ボールからインストールしてみます。
#tar xvzf FirebirdSS-1.0.2.908-0.tar.gz
#cd FirebirdCS-1.0.2.908-0
#./install.sh
Enter キーを押して開始するか、ctrl+C で中断するか聞かれるので、Enter キーを押下するとそれで完了です。アンインストールす
る時は、その下の scripts ディレクトリにある、preuninstall.sh と postuninstall.sh スクリプトを実行してください。
ClassicServer 版の場合は、inted または xinetd から起動されるので、上述したような起動時の問題はありません。Turbolinux でも、
インストールしてすぐにそのまま利用可能です。
Firebird の管理方法
つぎに Firebird の管理方法について触れたいと思います。製品版 InterBase には、IBConsole というアプリケーションが付属して
きますが、Firebird にはそうしたツールは付属してきません。
この IBConsole については、InterBase のソースコードが公開され時に、一緒にオープン・ソースとされたのですが、SourceForge で
は既に開発がストップしていて、Borland 社のコードセントラルで最新版のバイナリのみが入手可能な状態となっています。もちろん、
製品版の InterBase にはそれが日本語版であればきちんと日本語化されたものが付属してくるのですが、その後オープン・ソース版とし
ての開発がストップしているのはさみしい気がします15。
もっとも、IBPhoenix 社のサイトでリストアップされているように、Firebird を管理するためのツールは他にもたくさんあります。
本書では、以下のアプリケーションを利用した Firebird の管理方法を提案します。入手方法については、以下の一覧に併記した URL か
ら行ってください。その他のツールの一覧は IBPhoenix 社のサイトから、Downloads-Contributed の一覧をたどってください。
コントロールパネルアプレット:
Firebird Service Manager
URL: http://www.achim-kalwa.de/fb.html
サーバー管理コンソール:
IBOConsole
URL: http://www.mengoni.it/downloads.html
同日本語対応版
URL: http://www.apex-jp.com/business_dev.html
データベース管理アプリケーション:
Marathon
URL: http://sourceforge.net/projects/gmarathon
Firebird Service Manager
Firebird Service Manager は fbmgr.zip ファイルとして配布されているので、FBMgr.cpl を解凍して Windows のシステムフォルダ
(WINNT か Windows の直下にある System32)にコピーしてください。コントロールパネルに以下のアイコンが現れ、Firebird Service
Manager を起動できるようになります。
15
どうやら IBConsole の開発陣と Firebird の開発陣は仲が悪いようで、最新版の 3.44 でサポートされた index の一覧表示機能が
Firebird の Diarect3 で使用できない問題でもめたりしているようです。
Firebird Service Manager を起動してみましょう。以下の設定を行うことが出来ます。
①
②
③
④
Firebird Gurardian16と Firebird Server の起動状態を確認することが出来ます。
Windows 起動時の自動スタートアップの設定
Firebird をサービスとして起動する設定
Firebird Gurdian 使用の設定
そのほか、Enhanced タブでは Firebird Server のインストールディレクトリを確認できます。残念ながら、InterBase Server Manager
で可能なデータベースキャッシュとクライアントマップサイズの動的な変更には対応していません。IBPhoenix 社のサイトで紹介され
ているもう一つのコントロールパネルアプレット、Firebird Control もこの機能には対応していません。
コマンドラインツール
さて、GUI での管理ツールを号紹介する前に、Firebird 付属のコマンドラインツールについてふれておきたいともいます。Firebird
をインストールすると、gbak・gfix・gpre・gsec・gstat・iblockpr・isql などのコマンドラインツールがインストールされます。イ
ンストール先はインストール・ディレクトリ直下の bin ディレクトリです。
gbak はデータベースのバックアップ・復元を行うためのコマンドです。gfix はデータベースのいくつかのプロパティを設定します。
gpre は埋め込み SQL のプリプロセッサです。gsec はユーザーとグループの管理を行います。gstat はデータベースの統計情報を表示し
ます。iblockpr はロックマネージャーの情報を表示します。
ISQL の使い方
isql は対話型の SQL ツールで、データベースの作成・接続からデータの検索まで行えます。起動するとプロンプトが表示されますの
で、まずデータベースを作成してみましょう。下記の CREATE DATABASE 文を実行してください。データベースファイルのパス名、ユー
ザー名、パスワードはそれぞれシングルクォーテーションで囲んでください。データベースのパスは自分のシステムに合わせて変更し
てください。
Firebird サーバーと isql を実行しているマシンとが別の場合、データベース・パスの指定は次のようになります。
サーバー名/ポート番号:データベースのパス
サーバー名は IP アドレスか、あるいは名前解決が出来る環境であれば、コンピューター名でも構いません。必ずパス名との間にコロ
ンを入れてください。Firebird では InterBase からの拡張として、標準で使用するポート 3050 を変更することが出来ます。その場合、
サーバー名に続けて/とポート番号を記述してください。ここではデフォルトのまま使いますので、サーバー名のみで OK です。
文の区切りの ; を打ち込んでリターンキーを押すと SQL 文が実行されます。なにもエラーが表示されなければコマンドは完了してい
ます。指定したディレクトリの中身を確認してみてください。test.gdb が作成されているはずです。
SQL> create database 'c:\temp\test.gdb' user 'SYSDBA' password 'masterkey';
さて、データベースを作成したので、簡単なテーブルを作ってみましょう。CREATE TABLE 文でテーブル test を作成します。主キーを
指定する時は必ず先に NOT NULL 制約を付加して下さい。
SQL> create table test (id integer not null primary key,name varchar(10));
次に、データを挿入してみます。INSERT 文で test テーブルにデータを挿入します。データはなんでも構いませんが、主キーが重複
しないように気をつけて下さい。文字型のデータはシングルクォーテーションで囲んでください。
SQL> insert into test values(1,'tom');
SQL> insert into test values(2,'jelly');
SQL> insert into test values(3,'mickey');
最後に SELECT 文でデータを検索します。挿入したデータがすべて表示されれば OK です。
SQL> select * from test;
16
Firebird のサーバープロセスが落ちた時に再起動するための監視プロセスです。
(この項は初稿時に完璧に間違った記述でした。オ
ープンドキュメント化する際に修正しました)
ID
============
1
2
3
NAME
==========
tom
jelly
mickey
IBOConsole
IBOConsole はイタリア人の Lorenzo Mengoni さんが開発されている InterBase/Firebird 用の管理コンソールです。Mengoni さんのサ
イトは以下の URL となります。IBOConsole は Download コーナーからダウンロードすることが出来ます。また、筆者が簡易的に日本語
対応をしたものを公開しておりますので、前掲の URL よりダウンロードして利用してください。
IBOConsole は、Borland がオープンソースとした IBConsole を改良し、DB 接続のコンポーネントを IBX から IBObjects に変更したも
のです。その他にも、クエリーの結果を Excel に出力するなどの改良が加えられています。ただし、IBConsole と同様、WISQL のエディ
タ部分に TSynEdit というオープンソースのコンポーネントを使用しているため、日本語を入力すると文字化けしてしまうという問題が
あります。
(文字化けするだけで挿入や更新はちゃんと成功します)
本書では IBOConsole を Firebird サーバーの管理と、データベースの管理に限定して利用することとし、主にバックアップ用途での
使用法を解説します。IBOConsole では、トリガーの管理が出来ず、ストアド・プロシージャーの書き換えにも対応していません。
そこで、SQL 文の実行やテーブル・インデックス・トリガー・ストアドの作成などには後述する Marathon を使用することにします。
ただし、Marathon もいろいろと問題が起きるので、行ったり来たりしながら使うと言うことになると思います。
IBOConsole の起動画面は次のようになります。IBConsole にならって、画面の左側をツリーペイン、右側をワークペイント呼ぶこと
にします。
メニュー構成は以下のとおりです。
[Console]
[View]
-
[Server]
-
[Database]
-
[Exit]
[System Data]
[Large]
[Small]
[List]
[Details]
[Highlight Options …]
[Register …]
[Un-Register]
[Login …]
[Logout]
[Diagnose Connection …]
[User Securety …]
[View Logfile …]
[Properties …]
[Register …]
[Unregister]
[Connect]
[Connect As …]
[Disconnect]
[Create Database …]
[Drop Database]
[Maintenance]
[Backup/Restore]
[Backup …]
[Restore …]
[Modify Backup Alias …]
[Delete Alias]
[Database Statictics …]
[Sweep]
[Tools]
-
[Validation …]
[Transactrion Recovery …]
[Shutdown …]
[Database Restart]
[View Metadata …]
[Connected Users …]
[Properties …]
[Interactive SQL …]
[New connection …]
[Config Tools …]
サーバーの登録
IBOConsole ではサーバーやデータベースを Alias を使って登録し、毎回サーバーの IP アドレスやデータベース・ファイル名を指定
しなくても良いようになっています。最初に起動した時はサーバーが一つも登録されていないので、何も出来ませんから、まず[Server]
メニューの[Register …]を実行して、サーバーの登録を行います。ここではローカルサーバーの登録を行います。
ローカルサーバーの場合、Alias Name は入力できませんが、リモートサーバーの場合は PC_hogehoge といった名前を指定することが
出来ます。また、ローカルサーバーは API によるダイレクトな接続なので、Network Protocol も指定できません。もっとも、Server Name
に Localhost を指定して、Network Protcol を TCP/IP に指定すればローカルサーバーをいくつでも登録することが出来ます。Save Alias
Information のチェックを付けたままにしておけば、次回の IBOConsole 起動時に再度サーバーを登録する必要はありません。
ユーザーセキュリティ
User Name / Password は Firebird サーバーの初期設定では SYSDBA / masterkey になっています。このままではセキュリティホール
になるので、最低限パスワードを変更するように心がけましょう。やり方は後述します。
さて、ここでリモートマシンの Firebird を登録する場合は、Remote Server のラジオボタンを選択して、Server Name にマシン名ま
たは IP アドレスを、Network Protcol に有効なプロトコルを指定して、Alias Name をつけてやれば、登録することが出来ます。
こうして、サーバーを登録するとツリーペインの[InterBase Servers]の下に[Local Server]がグリーンのチェックマーク付で現れま
す。グリーンのチェックマークはサーバーにログオンしている状態を示しています。試しに、[Local Server]を右クリックし、コンテ
キストメニューから[Logout]を実行してください。グリーンのチェックマークが赤い×印に変わります。
もう一度、[Local Server]を右クリックして、コンテキストメニューから今度は[Login]を実行し、パスワードを入力してローカルサ
ーバーにログインします。[Local Server]の左側の[+]をクリックするか、[Local Server]のアイコンをダブルクリックするとツリー
が展開します。画面の状態は以下のようになっています。
ツリーペインの様子
ワークペインの様子
それでは、まず SYSDBA のパスワードを変更しましょう。ワークペインの User Security をダブルクリックして[User Information]
ダイアログを表示させましょう。
パスワードを変更するには、Password と Confirm Password に新しいパスワードを入力して、Apply ボタンをクリックします。
このダイアログボックスで、新しいユーザーを登録することも出来ます。New ボタンを押すと、Close ボタンが Cancel ボタンになり、
他のボタンは使用不可になります。User Name に新しいユーザー名を入力し、Password と Confirm Password を入力して Apply ボタンを
クリックします。
ユーザー名は 31 文字までで、大文字と小文字の区別はありません。また、パスワードは 32 文字までで、大文字と小文字が区別され
ますが、実際に有効なのは最初の 8 文字だけです。ユーザー名やパスワードに空白文字を含めることは出来ません。
既存のユーザーを削除する場合は、User Name ドロップダウンから該当するユーザーを表示させて、Delete ボタンをクリックしてく
ださい。SYSDBA はシステム管理上絶対に必要な組込みアカウントなので、削除できないようになっています17。
サーバーのプロパティ
次に、ワークペインから Properties をダブルクリックして、サーバのプロパティを表示させて見ましょう。Alias タブには先ほど登
録したサーバーの情報が表示されています。
General タブをクリックすると、接続している Firebird サーバーのバージョン情報とライセンス情報が上段に、下段に接続中のデー
タベースに関する情報が表示されています。
17
InterBase6 に付属の古い IBConsole を使うと SYSDBA を削除できてしまいますが、**絶対に**削除しないで下さい。Firebird を再イ
ンストールしない限り、ユーザーの追加や、変更を行うことが出来なくなります。
データベースの登録
次にサンプルデータベースの Employee.gdb を登録してみましょう。ツリーペインの Databases を右クリックして、コンテキストメニ
ューから Register を実行します。
[Register Database and Connect]ダイアログボックスが表示されるので、EMPLOYEE.GDB を選択して、ユーザー名とパスワードを入
力し、必ず[Default Character Set]を選択してから OK ボタンをクリックしてください。Employee.gdb ファイルは、<Firebird のイン
ストールフォルダ>\examples にインストールされています。Alias Name は、ここで入力した名称がツリーペインに表示されるのでわ
かりやすい名前にしておきます。今回はそのまま Employee.gdb としました。
デフォルト・キャラクタセットを指定しないと、Firebird は受け取ったデータをコード変換出来ないので、そのままデータベースに
格納してしまいます。すると、後々キャラクタセットの変更・変換などを行うことが出来なくなりますので、注意して下さい。
データベースの登録が正常に行われると、ツリーペインに次のような内容が表示されます。
それぞれ、データベースのドメイン、テーブル、ビュー、ストアド、UDF、ジェネレーター、例外、Blob フィルタ、SQL ロールを
示しています。
ドメインの一覧を次に示します。ワークペインに一覧表示されたドメインをダブルクリックすると、詳細な情報を表示することが出
来ます。また、この詳細表示のダイアログで内容を編集して保存することも出来ます。
しかし、ここでドメイン名やデータ長を変更しようとするとエラーが表示されてしまいます。どうやら、Employee.gdb の作成者が
CREATE DOMAIN 文で AS を使用しているのをエラーと判断しているようです。
/* Domain definitions */
CREATE DOMAIN ADDRESSLINE AS VARCHAR(30);
Firebird の SQL 構文としては間違っていませんが、InterBase のマニュアルなどによると AS は[AS]とされているので、オプション扱
いのようです。IBOConsole はこれをエラーと判断してしまうので、Employee.gdb のドメインを変更することが出来ません。
本書では、こうした作業は後述する Marathon で行うことにしますので、IBOConsole では、データベースの構造を確認するにとどめ
ておきます。
データベースのバックアップ・リストア
IBOConsole の利用目的として筆者がお勧めしたいのがデータベースのバックアップ・リストアです。Firebird には gbak.exe という
コマンドラインツールが付属していますが、これで管理をするのはやはりつらいものがあります。バッチファイルを作成してあげれば
いいのでしょうが、ここでは IBOConsole を使用して手軽に管理する方法をおすすめします。
IBOConsole で各 Firebird サーバーにログインすると、ツリーペインに Backup というアイコンが表示されます。この Backup アイコ
ンを右クリックすると、コンテキストメニューに[Backup …][Restore …][Modify Backup Alias …][Delete Alias]の4つのメニュ
ーが表示されます。このうち後の2つは一度もバックアップを行っていない場合は灰色表示されて使用できなくなっています。
それでは、まず Employee.gdb をバックアップしてみることにします。コンテキストメニューから[Backup]を実行してください。
Database Backup ダイアログが表示されます。
まず、データベースの Alias を指定します。データベースの Alias は先ほど登録する時に特に変更していなければ、Employee.gdb な
ので、ドロップダウンから選択してください。
次に Backup File(s)ですが、Server の選択はここでは Local Server のままで実行しますが、リモートの Firebird を利用している時
は、どの Firebird サーバーを使用してバックアップを行うかを指定できます。
このことは InterBase のマニュアルにも記載があり、IBConsole でも同様の指定が出来るようになっているのですが、IBConsole のソ
ースコードを見た限りでは、BackupService はあくまでもバックアップするデータベースの存在するマシンの Firebird サーバーで実行
されるようです。ですので、ここでは、Local Server のままとしておきますが、複数の Firebird サーバーが登録されている場合、ど
れを選んでも同じということになります。
さて、Filename(s)についてですが、バックアップファイル名とファイルのサイズを指定します。ファイル名は必ずフルパスで記述す
るようにしてください。ファイル名だけの場合は、カレントディレクトリにファイルが作成されるので、意図せぬところにファイルが
作成されてしまいます。
また、ここでは複数のファイルを指定することができます。複数のファイルを指定する場合には、ファイルサイズが意味を持ちます。
最低サイズはデータベースのページサイズですが、これでは意味が無いので、例えばフロッピーに入るサイズということで、約
1.4MB(1,457,664byte)を指定するとします。その場合、n 個のファイルを指定してたとすると、1 番目から n-1 番目のファイルまでは指
定のサイズどおり分割してデータが格納されますが、最後のファイルだけはサイズの指定に関わらずすべてのデータを格納するまで拡
張されます。
例えば、郵便番号データを格納してある YUBIN.GDB が約 25MB の容量があるとします。1 個目のファイルを YUBIN_01_1.GBK=1.4MB、2
個目のファイルを YUBIN_01_2.GBK=1.4MB、3 個目のファイルを、YUBIN_02_3.GBK=1.4MB としてみます。実際にバックアップを行うと、
1.4MB、1.4MB、4.5MB のファイルが出来上がります。
Firebird のデータベースは使用していると、だんだんと大きくなってきますので、バックアップファイルが実際のどれくらいの大き
さになるのかはやってみないとわかりません。ですから、ここでファイルをあまり細かく分けるという使い方はおいた方が良いと思い
ます。MO や CD-R、DVD-R などを利用することを考えれば、OS のファイルサイズ上限にだけ気をつければよいと思います。
バックアップオプション
さて、バックアップダイアログの右側に表示されているオプションについては以下のような内容となっています。
[Format]:Transportable、Non-transportable を選択できます。他の OS へバックアップファイルをファイルとして移動して、復元
する場合には Transportable を選択しないといけません。デフォルトは Transportable なので、通常はそのままで良いでしょう。
[Metadata Only]:デフォルトは False です。True を選択すると、データベースの構造のみがバックアップされます。データベース
を新しく一から使用したいときなどに利用します。
[Garbage Collection]:デフォルトは True です。Firebird のデータベースファイルには使用中にできた空き領域が虫食いのように残
ってしまい、次第にファイルサイズが肥大していきます。バックアップとリストアをする際に、ガーベージコレクションを指定すると、
この虫食い領域をクリーンアップしますので、リストア後のファイルサイズを小さくすることが出来ます。
[Transactions in Limbo]:データベースのトランザクションの 2 相コミットが失敗した場合や、システム障害などによってコミット
されていないトランザクションがある場合、どう処理するかを指定します。Process がデフォルトですが、こちらはトランザクション
を完了させます。Ignore を指定すると、Limbo トランザクション18は破棄されます。通常の使用では Limbo トランザクションが出来るこ
18
Limbo とはキリスト教の洗礼を受けていない人が死後に向かう地と言う意味です。天国と地獄の間を彷徨うという意味から、行き場
とはまずありえないので、デフォルトのままで良いでしょう。
[Checksums]:チェックサムはデータの整合性を検証するものです。デフォルトは Process となっているので、そのままにしておきま
す。チェックサムエラーが出た場合、バックアップは失敗します。データベースが破損していると思われるので、必要なら一つ前のバ
ックアップからデータを復元したほうが良いでしょう。
[Convert to table]:このオプションを使用すると外部テーブルを内部テーブルに変換することが出来ます。外部テーブルとは、
Firebird からアクセスできる固定長のテキストファイルのことです。詳しいことは省きますが、テキストファイルをテーブルとして扱
ってデータのインポート等を行えます。デフォルトは False なので、そのままで良いでしょう。
[Verbose OutPut]:メッセージの表示先を変更します。デフォルトは To Screen で、画面上に処理の状況が表示され、終了後にファイ
ルに保存することも出来ます。このオプションで、To File を選択するとファイル名の選択ダイアログが表示されるので、ファイル名
を指定してやれば、ファイルへの出力のみとすることも出来ます。None を選択すると処理の状況は出力されません。通常はデフォルト
のままで良いでしょう。
データベースのリストア
バックアップの次はデータベースのリストアです。バックアップの時はバックアップアイコンを右クリックしてコンテキストメニュ
ーを表示させましたが、今回はバックアップの Alias が登録されていますので、登録されている Alias のアイコンを右クリックして
[Restore …]を実行します。
こうして、Alias からリストアダイアログを表示させた場合、Alias が選択された状態でダイアログが表示されますが、Backup ダイ
アログやウインドウメニューから表示させた場合は、ドロップダウンから該当の Alias を選択してください。
ここで OK ボタンを押せば簡単にデータベースのリストアを行うことが出来ます。
※絶対に現在使用中のデータベースに対してリストアを行わないで下さい。すべての接続が切断されていることを確認してから、リ
ストアを行うようにしてください。
さて、リストアを実行する場合にも Filename(s)を複数指定することが出来ます。この機能を使用すると、もともと 1 つのデータベ
ースファイルで運用していたデータベースを 2 つ以上のファイルに分割して復元することが出来ますので、OS のファイルサイズ上限に
近づいた場合などに利用してください。複数のファイルを別々のハードディスクに配置することも出来ますので、パフォーマンスの改
善にも役立つかもしれません。もっとも、Oracle のようにテーブルごとにファイルを指定して、配置できるわけではないので、基本的
にはファイルサイズ上限を回避するための手段だと考えてください。19
このとき、バックアップの時とは違いサイズの指定は Pages となっていますので、リストアオプションで選択して Page Seize(Bytes)
×Pages で計算されるファイルサイズになるように指定してあげなくてはなりません。例えばページサイズが 2048 の時、CD-R に入るサ
イズと言うことで 600MB のデータベースにしたいと思ったら、307200 を指定します。
リストア・オプション
リストアのオプションについて以下に説明します。
[Page Size(Bytes)]:デフォルトは 4096 です。Firebird ではデータベースのアクセスを内部的にここで指定したページサイズ毎に行
います。したがって、データベースに格納されるデータが複数のページにまたがる場合、データへのアクセスにオーバーヘッドが生じ
ます。
デフォルトのサイズは 4096 ですが、例えば 4Kbyte よりも大きな Blob を扱ったり、1 レコードのサイズが 4096 より大きい場合には、
より大きな値を指定したほうが速度的な面で有利になります。
もっとも、ここで選択できるのは 1024, 2048, 4096, 8192, 16384 なので速度を優先するのであれば 16384 を指定することになりま
を失ったトランザクションデータをこう名付けたのでしょう。
Firebird のリリースノートによると最大の運用サイズの記録は約 980GB だそうです。
19
す。これも Firebird 独自の拡張で、InterBase では 8096 までしか指定できません。
逆に扱うレコードに Blob などが無く、レコードのサイズも小さい場合には、1024 や 2048 などのページサイズを指定するとデータベ
ースファイルのサイズを最小化できます。もっとも、現在のハードウェア環境を考えるとこういった使い方はあまり必要ないでしょう。
[Over Write]:デフォルトは False です。このオプションが True でないと、IBOConsole はデータベースファイルを上書きできません。
また、既存のデータベースファイルを上書きする場合、実行するユーザーは SYSDBA か上書きされるデータベースの所有者でなくてはな
りません。
[Commit After Each Table]:デフォルトは False です。このオプションを True に設定するとリストアは各テーブル単位で行われます。
False の場合、データベース全体でコミットされますので、データにエラーがあったり、制約違反になるような場合に、True を設定す
ることでエラーが出るテーブルより前に保存されているデータを復元することが出来ます。
どうしてもエラーが出てしまい、一部だけでもデータを復元したいという場合に True に設定してください。
[Create Shadow Files]:デフォルトは True です。Shadow ファイルは InterBase の基礎となったアーキテクチャーで、データベース
の物理的コピーを別のファイルに作成するものです。Firebird サーバーは Shadow ファイルが作成されると、本体と Shadow とを 2 相コ
ミットによって完全に同じ状態に保持します。Shadow ファイルが作成されているデータベースのバックアップを復元するときに、
Shadow
ファイルを再作成するために、このオプションを使用します。Shadow ファイルが無くてもエラーにはならないので、通常はデフォルト
のままで良いでしょう。
[Deactivate Indices]:デフォルトは False です。このオプションを使用すると、リストア中にインデックスを無効にし、再作成しな
いようにすることができます。ユニーク・インデックスが破損している場合などに、データベースのリストアが失敗することがあります
ので、その場合このオプションを True に設定して、データベースをリストアしてから重複した値を排除するなどし、インデックスを再
作成します。通常はデフォルトのままで良いでしょう。
[Validate Conditions]:デフォルトは Restore です。Ignore を設定すると参照整合性制約を無効にし、制約を再作成しないようにす
ることが出来ます。外部キーなどの参照整合性制約の違反によってデータが復元できない場合などに、このオプションを使用してデー
タを復元してから、再度参照整合性制約を設定します。通常はデフォルトのままで良いでしょう。
[Use All Space]:デフォルトは False です。このオプションを True に設定すると、リストア時にデータベースのページを 100%使用
してデータを復元するようになります。通常は 80%の使用率でデータが復元されます。Firebird は該当するページに関する追加データ
を同一のページになるべく保存しようとするので、この方がパフォーマンスが出ます。ただし、リードオンリー・データベースなどで、
ファイルサイズを少しでも小さくしたい場合などには、このオプションを使って 100%フィルを実行する意味があるかもしれません。通
常はデフォルトのままで良いでしょう。
[Verbose Output]: メッセージの表示先を変更します。デフォルトは To Screen で、画面上に処理の状況が表示され、終了後にファ
イルに保存することも出来ます。このオプションで、To File を選択するとファイル名の選択ダイアログが表示されるので、ファイル
名を指定してやれば、ファイルへの出力のみとすることも出来ます。None を選択すると処理の状況は出力されません。通常はデフォル
トのままで良いでしょう。
トム猫の独り言(1) IBConsole と ClassicServer
Linux 向けの ClassiceServer 版はインストールも簡単だし、問題も起きにくいようなので、本当はこちらをお勧めしたいところ
です。個人や小規模な企業・グループでの利用を想定すると、パフォーマンス上の問題が発生することもまずありません。
ところが、IBConsole 又は IBOConsole、Marathon の使用で問題があります。ClassiceServer 版は上記の管理コンソールから接
続できないのです。
これらの管理コンソールはデータベースへの接続に、isc_service_attach()API を利用しているのですが、ClassicServer 版に
はこの API が実装されていないのが原因です。InterBase 付属のものであれ、Borland から入手したものであれ、接続しようとす
ると以下のようなエラーが表示されてしまいます。
Cannot attach to services manager.
Services functionality will be supported in a later version of the product.
ClassicServer 版をサポートしている手軽な管理コンソールがあればよいのですが、残念ながら筆者はいまのことろそういったも
のを知りません。
Firebird プログラミング
見積書データベースの作成
さて、ここからは実際に Firebird サーバーを利用して簡単なデータベースを作成してみましょう。ここでは、見積書データベースを
素材として扱いたいと思います。
テーブルの構造は、顧客・商品の各マスタテーブルと見積書の基本情報・見積書の明細情報を以下のような内容で作成します。
テーブル構造
T_Customer
Cust_ID
Cust_Name
Cust_Yomi
Cust_Address1
Cust_Address2
Cust_Tel
Cust_Fax
Cust_Memo
//顧客テーブル
DOM_INT64 //主キー
DOM_NAME
DOM_NAME
DOM_ADDRESS
DOM_ADDRESS
DOM_TEL
//顧客 TEL
DOM_TEL
//顧客 FAX
DOM_MEMO
T_Product
Product_ID
Product_Name
Product_Yomi
Unit_Price
Unit_Name
DOM_INT64
DOM_NAME
DOM_NAME
DOM_MONY
T_Mitumori_Basic
Mitsu_B_ID
Cust_ID
MItsu_No
Mitsu_Date
Mitsu_Name
Mitsu_Yomi
//見積基本情報テーブル
DOM_INT64 //主キー
DOM_INT64 //顧客 ID
DOM_NO
//見積 No.
DOM_DATE //見積日付
DOM_NAME //件名
DOM_NAME //件名読み仮名
//顧客名称
//顧客名称読仮名
//顧客住所 1
//顧客住所 2
//備考
//商品テーブル
//主キー
//商品名称
//商品名称読み
//商品単価
DOM_NAME //商品単位
T_Mitsumori_Detail //見積明細テーブル
Mitsu_D_ID
DOM_INT64 //主キー
Mitsu_B_ID
DOM_INT64 //見積基本情報
Product_ID
DOM_INT64 //商品 ID
Unit_Price
DOM_MONY //商品単価
Quantity
DOM_INT4 //商品数量
Unit_Amount
//金額
(Unit_Price * Quantity)
各テーブルの列は、全てドメインを作成して指定しています。各ドメインの定義は以下のとおりです。
ドメイン定義
DOM_INT64
Numeric(18,0)
DOM_NAME
Varchar(20)
Default ''
DOM_ADDRESS
Varchar(20)
Default ''
DOM_TEL
Varchar(15)
Default ''
DOM_MEMO
Varchar(400)
Default ''
DOM_DATE
Date
Not Null
DOM_NO
Varchar(10)
Default ''
DOM_MONY
//主キー用
Default 0 Not Null
//名称用
character set SJIS_0208
Not Null
//住所用
character set SJIS_0208
Not Null
//電話番号用
character set ASCII
Not Null
//メモ用
character set SJIS_0208
Not Null
//日付用
Default 'TODAY'
//一連番号用
character set ASCII
Not Null
//金額用
Numeric(15,2)
DOM_INT4
Integer
Default 0 Not Null
//整数項目用
Default 0 Not Null
また、主キーはジェネレーターを利用して重複しない一連の数値を割り当てますので、以下のジェネレーターを作成します。
ジェネレーター定義
GEN_CUST_ID
GEN_Prod_ID
GEN_Mitsu_B_ID
GEN_Mitsh_D_ID
これらのジェネレーターから主キーに値を割り当てるためにトリガーを使う方法をご紹介しますが、これには少々問題があります。
トリガーによって主キーを設定する場合、データベースにデータが格納されるまでクライアントは主キーがどの値をとるかを感知で
きません。この場合、新しいデータを挿入した後でデータを更新・削除しようとする時に再度データセットを取得しなおさないといけ
ないことになってしまいます。
しかし、データの追加専用フォームを利用して(あるいは Web などから)データを挿入し、参照・変更する場合は別フォームというス
タイルを貫くのなら問題は生じません。
ここではトリガーを使用する方法をとりますが、追加・更新・削除を行うような場合は、クライアント側でジェネレータの値を取得
して設定した方が良い場合も多いので、その方法については後ほどご紹介します。
トリガー定義
TRG_SET_Cust_ID
TRG_SET_Product_ID
TRG_SET_Mitsu_B_ID
TRG_SET_Mitsh_D_ID
FOR
FOR
FOR
FOR
T_Cust
T_Product
T_Mitsu_B
T_Mitsh_D
BEFORE
BEFORE
BEFORE
BEFORE
INSERT
INSERT
INSERT
INSERT
Marathon
Marathon は Firebird と同様に、
SourceForge.net で開発が進められているオープンソースの Firebird/InterBase 管理用ツールです。
Marathon のプロジェクト・ホームページ の記述によると、InterBase 向けの商用 GUI としては初めてのものだったようです。
かなり以前から Patrick O'Keeffe 氏が彼の会社である Gimbal Software Service 社で開発・販売を続けてきたものを、2001 年の 6
月にオープン・ソースとして MPL の下で公開したとのことです。
SourceForge.net 上の Marathon Project
http://sourceforge.net/projects/gmarathon
Marathon のプロジェクト・ホームページ
http://alanti.net/firebird/marathon/
実際のところ開発の方はオープン・ソース化されて以降なかなか進んでいないようで、ダウンロード可能なコンパイル済みバイナリは
2.0.0_Beta と 1.5.0_Rel の 2 つだけで共にタイムスタンプは 2001 年 6 月 4 日となっています。CVS リポジトリを見る限りでは徐々に
修正が行われているようです。SourceForge の Forum 条では”You are died?”という質問ならぬ質問も出ていましたが、まもなく主要な
開発者が戻ってきて新しいバージョンをリリースできるだろうと返答されていました。
同 Forum 上ではバージョン 2 で dialect3 のデータベースに接続できない時があると言う質問も出されており、開発者から CVS 上では
修正されているがバイナリの提供にはもう少しかかるという回答がありました。
手元にある 2.0.0_Beta で Diralect3 のデータベースに接続していると、確かに時々変なエラーを返してきます。また 1.5.0-Rel では
可能だったフィールドのプロパティ表示が出来ないなど、結構問題を抱えています。本書では開発中のバージョン 3.0 のスナップショ
ットを使いつつ、バグのあるところについてはバージョン 1.5Rel を使っていきたいと思います。
Marathon のインストール
まずはインストールから始めましょう。前述した SourceForge の Marathon プロジェクトのページから、
「Latest File Releases」の
欄に下側にある[Vew All Project Files]をクリックして表示されるページから、Marathon_1.5.0_Rel.zip をダウンロードします。こ
れを解凍するとセットアップ用のファイルが一式出てくるので、setup.exe を実行してインストールします。
次に Marathon Porject のプロジェクト・ホームページの下の方にある「SnapShots」の項から、「Here you will find binary and
sourcecode snapshots which are done by "build.bat official_snapshots". 」の「Here」のところのリンクをクリックすると表示さ
れるページから、Marathon_Binary.Zip ファイルをダウンロードしてください。解凍すると、setup.exe というファイルが出てくるので、
これを実行します。2002 年 12 月 22 日現在のビルドナンバーは 3.0.0.21_Beta です。
Marathon の起動
プログラムメニュー「Marathon 3.0」から Marathon を起動します。起動直後にはワンポイントメニューが出ますから、次回も表示す
るのチェックを外して表示しないようにしてしまいましょう。
起動時のスプラッシュスクリーン
Marathon のメインウィンドウ
起動直後は上に示すメイン・ウインドウ(というかツールバー)と、空の Browser ウインドウが表示されているだけです。まずはツ
ールバーの左端にある New Project ボタンをクリックして、新しいプロジェクトを作成しましょう。Marathon では、データベースの管
理にプロジェクトという単位を使用します。プロジェクトで管理されるのは、Firebird サーバー、データベースファイル名、ユーザー
名、パスワード、デフォルトキャラクタセット、SQL ロールなどです。
順を追ってみます。まず、New Project ダイアログでプロジェクト名を指定し、
① システムテーブルの表示・非表示、
② システム生成ドメインの表示・非表示、
③ ウインドウの位置を保存
の 3 つのオプションをチェックボックスで指定します。SQL のヒストリを何回まで残すかを数値で指定し、デフォルトキャラクタセ
ットを選択します。Windows の場合、通常は SHIFTJIS Character Set を選択します。
OK ボタンを押すと、New Connection ダイアログが表示されます。コネクション名を指定し、データベースファイル名を指定します。
ローカルファイルの場合は、ファイル選択ダイアログを表示させて選択することが出来ます。リモートサーバーのデータベースの場合
は、サーバー名:データベースファイルの絶対パスと表記します。Charset には SJIS_0208 を指定し、ユーザー名・パスワードを入力
したら、保存する場合は Rmember Password をチェックしてください。SQL Role と SQL Dialect は必要に応じて入力・変更してくださ
い。
こうして、プロジェクトの作成時に一つのコネクションを作成しますが、一つのプロジェクトに複数のコネクションを含めることも
可能です。その場合は、Marathon のメニューから[Project]-[New Connection]を実行するか、Browser ウインドウから[Connections]
を右クリックしてコンテキストメニューから[New Connction]を実行します。問題が一つあります。コネクションを追加することは出来
ますが、削除することが出来ません。今後のバージョンアップに期待しましょう。
新規データベースの作成
さて、今度は一から新しいデータベースを作成してみましょう。まず、[File]メニューから、[Close Project]を実行し、現在のプロ
ジェクトを閉じます。
次に、[File]-[Create Database]メニューを実行します。[Name]欄にはデータベースファイル名を入力し、ユーザー名・パスワード
にはこのデータベースの所有者となるユーザーを指定します。Firebird サーバーに新しいユーザーアカウントを作成していなければ、
SYSDBA を指定しておけばよいでしょう。見積書データベースを作成することとし、ファイル名は Mitsumori.gdb としておきます。
[Page Seize]には例によって 1024 から 8192 までの値を選択できますが、Marathon では 16384 を指定することが出来ません。16384
のページサイズを使用したい場合は IBOConsole でデータベースを作成してから Marathon に登録する方がいいかもしれません。
[Char Set]には SJIS_0208 を指定し、[Dialect]には 3 を指定しておきます。
[Next]ボタンをクリックすると、[Use Multble Files]チェックボックスだけのページが現れます。ここでチェックをすると、複数フ
ァイルを指定するグリッドなどが表示されますので、必要な場合はチェックをしてください。今回はそのままチェックせずに次のペー
ジへ移動します。
次のページではデータベースの作成後に SQL スクリプトを実行するかどうかの指定と、作成したデータベースを Marathon のプロジェ
クトとして登録するかどうかの指定をします。見積書データベースなので、プロジェクト名を Mitsumori、コネクション名を MitsumorCN
としました。
データベースの作成が終了するとブラウザ・ウインドウに MisumoriCN が表示され、各データベース要素がツリー表示されます。表示
される要素は以下のとおりです。
[User Domains]:ユーザー定義のドメイン
[Tables]:テーブル
[Views]:ビュー
[Stored Procedures]:ストアドプロシージャー
[Triggers]:トリガー
[Generrators]:ジェネレーター
[Exceptions]:例外
[User Defined Procedures]:ユーザー定義関数
ドメインの作成
まず、ドメインを定義していきます。ドメインは、データベース全体に対して有効なカラムの定義です。
例えば、現状で電話番号を格納するカラムにはハイフンを入れて 13 桁必要です。しかし将来的には 20 桁の電話番号が使用されるか
もしれません。それを見越してあらかじめ 20 桁を用意するのはスペースの無駄ですが、変更が必要となった際に、複数のテーブルのカ
ラムを一つづつ変更するのも労力を必要とします。
その場合、ドメインを定義して各テーブルの電話番号カラムをドメインによって定義しておけば、桁数を変更しなくてはならなくな
った時にドメインを変更するだけで、全てのテーブルのカラム定義を変更することができるのです。SQL 文では以下のように行います。
--CREATE DOMAIN 文の構文-CREATE DOMAIN ドメイン名 [AS] <データ型>
[DEFAULT ( 文字列
| NULL
| USER
| CURREN_USER
| CURRENT_ROLE)]
[NOT NULL]
[CHECK <チェック制約>]
[COLLATE コレーションオーダー];
<データ型>には列定義で有効なデータ型を指定します。後述の CREATE TABLE 文を参照してください。
<チェック制約>にはチェック制約を指定します。有効なデータの制限など、データの整合性をここでチェックします。
コレーションオーダーには各キャラクタセットで有効なコレーションオーダーを指定します。コレーションオーダーは、各キャラク
タセットで使用可能な、ソート順序のことです。
※CURRENT_USER,CURREN_ROLE は Firebird 独自の拡張です。CURREN_USER と USER は同一の値をとり、データベースへ接続しているユ
ーザー名を返します。CURRENT_ROLE はデータベースに接続しているユーザーの SQL ロールを返します。SQL ロールが設定されていない
時は NONE を返します。
Firebird/InterBase では文字型のデータのサイズを各キャラクタセットの文字数で数えます。半角換算で 40 桁ほしいと思った時、
キャラクタセット SJIS_0208 では 20 を指定しないといけません。全角文字が入力されないのなら、列のキャラクタセットで ASCII 等を
指定します。
NUMERIC(10 以上[, 精度])とすることで、
Dialect3 で導入された 64bit 整数値を格納することが出来ます。GENERATOR の返す値が 64bit
整数値になったので、連番で使用する主キーなどにはこうしたドメインを使用するのが良いと思われます。有効桁数は最大 18 なので、
NUMERIC(18,0)とすると 64bit 整数を最大限利用できます。
ドメインによって列のデータ型を指定して作成されたテーブルの各カラムの定義は、以下のようにしてドメインを変更することで変
更することが出来ます。
ドメイン定義の変更の例
ALTER DOMAIN DOM_PHONE_NO SET TYPE VARCHAR(20);
さて、では Marathon を使用してドメインを定義してみましょう。まず、ブラウザ・ウインドウの[User Domains]アイコンを右クリッ
クして、[New]-[New Object]を実行してください。Domain [new_domain]ダイアログが表示されます。
[Domain]に「DOM_ID」を入力し、[Type]からデータ型「NUMERIC」を選択します。NUMERIC を選択すると、すぐ下に[Precision]と[Scale]
を選択する欄が表示されるので、それぞれを 18 と 0 に指定します。スピンボタンを使用すると 15 までしか指定できませんが、直接入
力するといくつでも指定できます(19 以上はエラーになります)。[Precision]は有効桁数を、[Scale]は小数点以下の桁数を示します。
[Array]は配列型の指定に使用するので、今回は使用しません。[Not Null]チェックボックスをチェックして、[Default]タブを選択
して 0 を入力します。
ツールバーのコンパイルボタンをクリックすると、Compling ダイアログが表示され、
「Operation Completed - No Errors」とメッセ
ージが表示されれば OK です。ブラウザ・ウインドウの[User Domains]の下に新しいドメインが出来ていることが確認できます。
同様にして先ほどあげたドメインを全て作成します。
ジェネレーターの作成
次にジェネレーターを作成します。ジェネレーターはシステムに一意な数値を管理してユーザーに提供する機能です。Oracle で言え
ばシーケンスにあたる機能です。
SQL 文では以下のようにして作成します。
--CREATE GENERATOR 文の構文-CREATE GENERATOR generator 名;
Oracle のような、START WITH 句での初期値の指定や INCREMENT BY 句による増分指定はありません。これらは、SET GENERATOR 文
と GEN_ID()文で指定します。
--SET GENERATOR 文の構文-SET GENERATOR ジェネレーター名 TO 設定値;
SET GENERATOR 文を利用すると任意の時点で任意の値にジェネレーターを初期化することが出来ます。この機能を利用すると伝票番
号を自動で振りたいが、1 番から 9999 番まででサイクリックしたいというようなリクエストに簡単に答えることが出来ます。設定値は
64bit 整数値(-263~263)を指定します。
--GEN_ID()文の構文-GEN_ID(ジェネレーター名, 増分値);
GEN_ID()文はジェネレーターから新規の値を得るために使用します。ここで、増分値を指定した分だけインクリメントした値が戻さ
れます。増分値も 64bit 整数値で指定できます。つまり、デクリメントすることも出来るわけです。
では Marathon を使用してドメインを定義してみましょう。まず、ブラウザ・ウインドウの[Generators]アイコンを右クリックして、
[New]-[New Object]を実行してください。Generator [new_generator]ダイアログが表示されます。
[Generator Name]に「GEN_Cust_ID」を入力して[Save]ボタンをクリックしてください。Compling ダイアログが表示され、
「Operation
Completed - No Errors」とメッセージが表示されれば OK です。この時、[Save]ボタンではなく、ツールバーの[Compile]ボタンでコン
パイルを実行するとエラーが起きてしまいますので、現状ではかならず[Save]ボタンを利用するようにしてください。
こうして、いったん作成されたジェネレーターの値はこのダイアログボックスから値を変更して[Reset Value]ボタンをクリックする
ことで、簡単に変更することが出来ます。
Firebird では DROP GENERAOTR 文が追加されているので SQL からも簡単にジェネレーターを削除することが出来ますが、Marathon を
利用するとブラウザウィンドウからジェネレーターを選択して、コンテキストメニューの[Drop]を実行すると削除できますので、
InterBase をお使いの場合にも簡単です。
では、同様にして先ほどあげたジェネレーターを全て作成しましょう。
テーブルの作成
それではテーブルの作成にかかりましょう。Marathon ではテーブルの作成もビジュアルに行うことが出来ますが、まずは SQL 文から
見てみます。Create Table 文の構文は複雑なので、ここでは最小限の説明に留めます。
--CREATE TABLE 文の構文—
CREATE TABLE テーブル名 (
<列定義>[, <列定義> | <テーブル制約>,・・・]);
<列定義> = 列名
{ データ型
| COMPUTED [BY] (計算式)
| ドメイン名}
[DEFAULT { 文字列
| NULL
| USER
| CURRENT USER
| CURRENT ROLE}]
[NOT NULL]
[<列制約>]
[COLLATE <コレーションオーダー>]
<データ型> =
{ SMALL INT | INTEGER | FLOAT | DOUBLE PRECISION}|
{ DATA | TIME | TIMESTAMP}|
{ DECIMAL | NUMERIC} [(有効桁数, 精度)]|
{ CHAR | CHARACTER
| CHARACTER VARYING
| VARCHAR}
[(文字数)]
[CHARACTER SET キャラクタセット名]|
{BLOB [SUB TYPE {数値 | サブタイプ名}]
[SEGMENT SIZE 数値]
<列制約> = [CONSTRAINT 制約名]
{ UNIQUE
| PRIMARY KEY
| REFERENCES 別テーブル名[(列名[, 列名・・・])]
[ON DELETE { NO ACTION
| CASCADE
| SET DEFAULT
| SET NULL}]
[ON UPDATE { NO ACTION
| CASCADE
| SET DEFAULT
| SET NULL}]
| CHECK (チェック制約)}
<テーブル制約> = [CONSTRAINT 制約名]
{{PRIMARY KEY | UNIQUE} (列名[, 列名・・・])
| FOREGIGN KEY (列名[, 列名・・・])
REFERENCES 別テーブル名[(列名[, 列名・・・])]
[ON DELETE { NO ACTION
| CASCADE
| SET DEFAULT
| SET NULL}]
[ON UPDATE { NO ACTION
| CASCADE
| SET DEFAULT
| SET NULL}]
| CHECK (チェック制約)}
配列型の指定や、チェック制約の記述方法などは省略しました。実際にどのような SQL 文を記述するのかは、以下にサンプルを記述
します。
T_Customer テーブルの作成 SQL 文
CREATE TABLE T_Customer (
Cust_ID
DOM_INT64 PRIMARY KEY,
Cust_Name
DOM_NAME,
Cust_Yomi
DOM_NAME,
Cust_Address1 DOM_ADDRESS,
Cust_Address2 DOM_ADDRESS,
Cust_Tel
DOM_TEL,
Cust_Fax
DOM_TEL,
Cust_Memo
DOM_MEMO);
T_Product テーブルの作成 SQL 文
CREATE TABLE T_Product (
Product_ID
DOM_INT64 PRIMARY KEY,
Product_Name
DOM_NAME,
Product_Yomi
DOM_NAME,
Unit_Price
DOM_MONY,
Unit_Name
DOM_NAME);
T_Mitsumori_Basic テーブルの作成 SQL 文
CREATE TABLE T_Mitsumori_Basic (
Mitsu_B_ID
DOM_INT64 PRIMARY KEY,
Cust_ID
DOM_INT64,
Mitsu_No
DOM_NO,
Mitsu_Date
DOM_DATE,
Mitsu_Name
DOM_NAME,
Mitsu_Yomi
DOM_NAME,
FOREIGN KEY (Cust_ID)
REFERENCES T_Customer (Cust_ID)
ON UPDATE CASCADE);
T_Mitsumori_Detail テーブルの作成 SQL 文
CREATE TABLE T_Mitsumori_Detail(
Mitsu_D_ID
DOM_INT64 PRIMARY KEY,
Mitsu_B_ID
DOM_INT64,
Product_ID
DOM_INT64,
Unit_Price
DOM_MONY,
Quantity
DOM_INT4,
Unit_Amount
COMPUTED BY
(Unit_Price * Quantity),
FOREIGN KEY (Mitsu_B_ID)
REFERENCES T_Mitsumori_Basic (Mitsu_D_ID)
ON UPDATE CASCADE,
FOREIGN KEY (Product_ID)
REFERENCES T_Product (Product_ID)
ON UPDATE CASCADE);
この SQL 文を SQL エディタに入力してもテーブルを作成できますが、GUI を使ってテーブルを作成してみます。まずは、ブラウザウ
ィンドウの[Tables]を右クリックしてコンテキストメニューから[New]-[New Object]を実行します。
[Create New Table and Add First Column]ダイアログが表示されるので、[Table Name]に「T_Customer」を入力し、一つ目の列名で
ある「Cust_ID」を入力します。下側に表示されているデータ型の指定で、[Domain]タブをクリックして、ドメイン名一覧から「DOM_INT64」
を指定します。上部のタブから[Constraint]を選択肢、
「PRIMARY KEY」を入力します。最後に[OK]ボタンを押して変更を保存してくだ
さい。
フィールドを追加するためにはいったんこのダイアログボックスを閉じなくてはなりません。右上のクローズボタンでダイアログを
閉じて、ブラウザウィンドウの[Tables]ノードから、今追加した[T_Customer]をダブルクリックして、テーブルエディタ・[Table
–[T_Customer]]を表示させます。
※実は現状の Marathon ではテーブル等の追加を行った後にブラウザウインドウのツリーを操作できなくなり、エラーが出て終了する
ことが出来なくなってしまうと言うバグがあります。しかし、単にいったん表示が出来なくなるだけなので、上記の手順を繰り返して
テーブルを 4 つ作成してからタスクマネージャーで Marathon をいったん終了させてから、再起動してください。
テーブルエディタ上で右クリックしてコンテキストメニューから[New]-[Field]を実行すると先ほどの[Create New Table…]と同じ
[New Column]ダイアログが表示されるので、必要なフィールドを追加していきます。
列の制約として PRIMARY KEY 句や REFERENCES 句を設定する時は、[New Column]ダイアログの[Constraint]ページに記述してください。
FOREIGN KEY 制 約 等 を テ ー ブ ル に 設 定 す る 時 は 、 テ ー ブ ル エ デ ィ タ の [Constraint] ペ ー ジ で コ ン テ キ ス ト メ ニ ュ ー か ら
[New]-[Constraint]を実行して、[New Constraint]ダイアログから設定します。
トリガーの作成
次にトリガーを作成します。トリガーを作成する時の SQL 文は次のようになります。
--CREATE TRIGGER 文の構文—
CREATE TRIGGER トリガー名 FOR テーブル名
[ACTIVE | INACTIVE]
{BEFORE | AFTER}
{DELETE | INSERT | UPDATE}
[POSITION 数値]
AS <トリガー本文> 区切文字
<トリガー本文> =
[<ローカル変数の宣言>] <ブロック>
<ローカル変数の宣言> =
DECLARE VARIABLE 変数名 <データ型>;
[DECLARE VARIABLE 変数名 <データ型>; …]
<ブロック> =
BEGIN
<ブロック | ステートメント>
[<ブロック | ステートメント>
END
・ACTIVE, INACTIVE:任意項目。トリガーを起動するか、どうかを指定。
・BEFORE, AFTER:トリガー起動のタイミングを指定。
・DELETE, INSERT, UPDATE:トリガーを起動するテーブルの動作を指定。
・POSITION:トリガーの起動順序。同一動作に対するトリガーの起動する順序を 0~32767 の数値で指定します。0 が最初に起動される
トリガーで、デフォルト値は 0 となります。同一の番号を複数指定することが可能ですが、その場合起動順序不定となります。
・DECLARE VARIABLE:トリガーで使用するローカル変数の宣言をここでします。データ型は有効な SQL 型となります。
・区切文字:ISQL 等の複数の SQL を実行可能な環境で CREATE TRIGGER 文を実行する場合、トリガー言語の区切文字であるセミコロン
が、SQL 文の区切と判別できないため、SET TERM 文で区切文字を変更してからトリガー言語を記述します。
以下に T_Customer テーブルの Cust_ID を自動的に設定するトリガーを示します。この例では、ISQL で実行可能なように区切文字を
変更しています。
SET TERM ; !!
CREATE TRIGGER TRG_GET_Cust_ID FOR T_Customer
BEFORE INSERT POSITION 0 AS
BEGIN
NEW.Cust_ID = GEN_ID(GEN_Cust_ID, 1);
END !!
SET TERM !! ;
「New」はトリガーの中でのみ使用可能なコンテキスト変数で、これから設定される新しい値を示しています。逆に「Old」は変更前
の値を示しています。これを使うと、例えばあるレコードの変更に伴って履歴を残すとか、変更の回数をカウントするとかいった使い
方が出来ます。
New と Old の使用可能な位置は以下の通りです。
INSERT
UPDATE
DELETE
NEW
BEFORE のみ
BEFORE のみ
×
OLD
×
○
○
では、次に Marathon を使ってのトリガーの作成方法を示します。まず、ブラウザウィンドウから[Triggers]を右クリックして、コン
テキストメニューから[New]-[New Object]を実行します。
[Name]欄にトリガー名を入力し、[For]欄でドロップダウンからテーブル名を選択します。下部で、「active」はそのままにして、そ
の下のドロップダウンから「before insert」を選択します。[Position]は 0 のままにしておきます。ここで、[OK]ボタンをクリックす
ると、トリガー・エディタが開きます。
上部には先ほど入力した内容でトリガーのヘッダーが生成されているので、下部の begin と end の間に本文を書いていきます。ここ
で作成するトリガーは全て前述の例と同様で、以下のとおりとなります。
TRG_SET_Cust_ID の本文
NEW.Cust_ID = GEN_ID(GEN_Cust_ID, 1);
TRG_SET_Product_ID の本文
NEW.Product_ID = GEN_ID(GEN_Prod_ID, 1);
TRG_SET_Mitsu_B_ID の本文
NEW.Mitsu_B_ID = GEN_ID(GEN_Mitsu_B_ID, 1);
TRG_SET_Mitsu_D_ID の本文
NEW.Mitsu_D_ID = GEN_ID(GEN_Mitsu_D_ID, 1);
ストアドプロシージャーの作成
最後にストアドプロシージャーを作成します。ここでは、データの挿入と表示に利用します。ストアドプロシージャーを作成する SQL
の構文は以下の通りです。
--CREATE PROCEDURE 文の構文—
CREATE PROCEDURE プロシージャー名
[( パラメータ名 <データ型>
[, パラメータ名 <データ型>・・・])
[RETURNS ( パラメータ名 <データ型>
[, パラメータ名 <データ型>・・・])]
AS <プロシージャー本文> 区切文字
<プロシージャーー本文> =
[<ローカル変数の宣言>] <ブロック>
<ローカル変数の宣言> =
DECLARE VARIABLE 変数名 <データ型>;
[DECLARE VARIABLE 変数名 <データ型>; …]
<ブロック> =
BEGIN
<ブロック | ステートメント>
[<ブロック | ステートメント>
END
基本的な構文はトリガーと同様ですが、ストアドプロシージャーの場合はパラメーターを受け取ることが出来るのと、戻り値を設定
することが出来ます。
ストアドプロシージャーでは様々なことが出来ますが、Firebird の特徴である結果セットを返すストアドプロシージャーの例を示し
ます。この例では、見積基本情報 ID を渡すと、それに関連する明細情報を結果セットとして返します。
それぞのれプロシージャーの最後の方にある SUSPEND に注意してください。Firebird のストアドでは、この SUSPEND コマンドが実行
されると戻り値を呼び出し元の FETCH に対応して戻すようになっています。この機能があることで、複数の行をあたかもテーブルのよ
うに返すことの出来るストアドを実現しているのです。
ストアドのパラメータで指定する P_Mitsu_B_ID と P_Product_ID は本当は NUMERIC(18,0)としたいところですが、IBOConsole でも
Marathon でもストアドプロシージャーの実行コマンドでエラーが出るため、INTEGER としました。
SET TERM ; !!
CREATE PROCEDURE
SP_Mitsu_D_Mitsu_B (P_Mitsu_B_ID INTEGER)
RETURNS (R_Mitsu_D_ID
NUMERIC(15),
R_Product_Name VARCHAR(20),
R_Unit_Price
R_Quantity
R_UNit_Amount
NUMERIC(15,2),
INTEGER,
NUMERIC(15,2))
AS BEGIN
FOR
SELECT MD.Mitsu_D_ID,
P.Product_NAME,
MD.Unit_Price,
MD.Quantity,
MD.Unit_Amount
FROM
T_Mitsumori_Detail MD,
T_Product P
WHERE
MD.Mitsu_B_ID = :P_Mitsu_B_ID
AND
MD.Product_ID = P.Product_ID
INTO
:R_Mitsu_D_ID,
:R_Product_NAME,
:R_Unit_Price,
:R_Quantity,
:R_Unit_Amount
DO
SUSPEND;
END !!
SET TERM !! ;
次の例は、やはり見積基本情報 ID に従って、明細情報の金額欄を合計して返すものです。この場合、結果セットは必ず 1 行となりま
す。
SET TERM ; !!
CREATE PROCEDURE
SP_SUM_Mitsu_D (P_Mitsu_B_ID INTEGER)
RETURNS (R_Sum_Price NUMERIC(15,2))
AS BEGIN
SELECT SUM(Unit_Amount) FROM T_Mitsumori_Detail
WHERE Mitsu_B_ID = :P_Mitsu_B_ID
INTO :R_Sum_Price;
SUSPEND;
END!!
SET TERM !! ;
また、例えば前述の見積明細に行番号を振って表示させたいとします。その場合、FOR SELECT ・・・ DO 文を使って処理します。
SET TERM ; !!
CREATE PROCEDURE
SP_Mitsu_D_Mitsu_B2 (P_Mitsu_B_ID INTEGER)
RETURNS (R_Row_No
INTEGER,
R_Mitsu_D_ID
NUMERIC(15),
R_Product_Name VARCHAR(20),
R_Unit_Price
NUMERIC(15,2),
R_Quantity
INTEGER,
R_UNit_Amount NUMERIC(15,2))
AS
DECLARE VARIABLE INT_ROW_NO INTEGER;
BEGIN
INT_ROW_NO = 1;
FOR
SELECT MD.Mitsu_D_ID,
P.Product_NAME,
MD.Unit_Price,
MD.Quantity,
MD.Unit_Amount
FROM
T_Mitsumori_Detail MD,
T_Product P
WHERE
MD.Mitsu_B_ID = :P_Mitsu_B_ID
AND
MD.Product_ID = P.Product_ID
INTO
:R_Mitsu_D_ID,
:R_Product_NAME,
:R_Unit_Price,
:R_Quantity,
:R_Unit_Amount
DO BEGIN
R_ROW_NO = INT_ROW_NO;
INT_ROW_NO = INT_ROW_NO + 1;
SUSPEND;
END
END !!
SET TERM !! ;
また、今回のテーブルでは値引き等に対応できるように T_Mitsumori_Detail テーブルにも Unit_Price 列があります。Unit_Price 列
の値はプログラム的に挿入してあげないといけません。そのためのストアドプロシージャーは以下のようなります。
SET TERM ; !!
CREATE PROCEDURE
SP_Insert_Mitsu_D (P_Mitsu_B_ID INTEGER,
P_Product_ID INTEGER,
P_Quantity
INTEGER)
AS
DECLARE VARIABLE NUM_Unit_Price NUMERIC(15,2);
BEGIN
NUM_Unit_Price = 0;
SELECT
Unit_Price
FROM
T_PRODUCT
WHERE
Product_ID = :P_Product_ID
INTO
:NUM_Unit_Price;
INSERT INTO
T_Mitsumori_Detail
(Mitsu_B_ID,
Product_ID,
Unit_Price,
Quantity)
VALUES
(:P_Mitsu_B_ID,
:P_Product_ID,
:NUM_Unit_Price,
:P_Quantity);
END !!
SET TERM !! ;
データベースへのデータの挿入
では、動作確認のためにデータを用意してみましょう。以下の SQL 文を実行してデータベースにデータを挿入します。
※Marathon3.0 では日本語のデータを Insert することが出来ませんので、Marathon1.5 を使用して SQL エディタから実行してくださ
い。IBOConsole では、WISQL で日本語が文字化けしてしまいますが、データの挿入や更新はきちんとされます。今のところ、一長一短
ですね。
INSERT INTO T_CUSTOMER
(CUST_NAME,
CUST_YOMI,
CUST_ADDRESS1,
CUST_ADDRESS2,
CUST_TEL)
VALUES
('株式会社アペックス',
'か)あぺっくす',
'東京都世田谷区',
'駒沢 2-11-3 4F',
'03-5431-1711');
INSERT INTO T_PRODUCT
(Product_Name,
Product_Yomi,
Unit_Price,
Unit_Name)
VALUES
('Delphi マガジン Vol.26',
'Delphi まがじん 26',
1000,
'冊');
INSERT INTO T_PRODUCT
(Product_Name,
Product_Yomi,
Unit_Price,
Unit_Name)
VALUES
('BCB6 基礎プラグラミング',
'BCB6 きそぷろぐらみんぐ',
2667,
'冊');
INSERT INTO T_Mitsumori_Basic
(Cust_ID,
Mitsu_No,
Mitsu_Date,
Mitsu_Name,
Mitsu_Yomi)
VALUES
(1,
'A0001',
'TODAY',
'書籍売上',
'しょせきうりあげ');
明細データの追加にはストアドプロシージャーを利用します。下記の SQL 文は IBOConsole の WISQL にて使用可能ですが、実行するとエ
ラーが表示されてしまいます。データはきちんと挿入されているのですが、この辺何とかならないものでしょうか。
Execute Procedure }
SP_Insert_Mitsu_D
(1,
1,
5);
Execute Procedure
SP_Insert_Mitsu_D
(1,
2,
1);
データベースからのデータの表示
では、これらのデータを先ほどのストアドプロシージャーを利用して表示させて見ましょう。まずは、合計金額です。
SELECT * FROM SP_Sum_Mitsu_D(1);
R_SUM_PRICE
===========
14667
次に関連する明細行を表させます。(結果は次ページ)
SELECT * FROM SP_Mitsu_D_Mitsu_B(1);
明細のデータは何度か挿入と削除を繰り返したので、番号が Mitsu_D_ID はとびとびになっています。これを、行番号を付加して表示
させるとこうなります。(結果は次ページ)
SELECT * FROM SP_Mitsu_D_Mitsu_B2(1);
SELECT * FROM SP_Mitsu_D_Mitsu_B(1);の実行結果
R_MITSU_D_ID R_PRODUCT_NAME
R_UNIT_AMOUNT
============
======================
=============
1
Delphi マガジン Vol.26
1000
2
BCB6 基礎プラグラミング 2667
3
Delphi マガジン Vol.26
1000
6
Delphi マガジン Vol.26
1000
R_UNIT_PRICE
============
5
1
3
4
R_QUANTITY
==========
5000
2667
3000
4000
SELECT * FROM SP_Mitsu_D_Mitsu_B2(1);の実行結果
R_ROW_NO
========
1
2
3
4
R_MITSU_D_ID
============
1
2
3
6
R_PRODUCT_NAME
R_UNIT_PRICE R_QUANTITY R_UNIT_AMOUNT
====================== ============ ========== =============
Delphi マガジン Vol.26 1000
5
5000
BCB6 基礎プラグラミング 2667
1
2667
Delphi マガジン Vol.26 1000
3
3000
Delphi マガジン Vol.26 1000
4
4000
トム猫の独り言(2) オープンソースとライセンス
先に Firebird のライセンスが InterBase Public License であること、IPL が MPL の修正版であることを記載しました。IPL で
は公開したソースコードに対して行われた修正を、ボーランド社が独占的(Proprietary)ソフトウェア に使用することを可能とす
る条項が含まれています。つまり、Borland 社は改良点を取り込めるが、取り込んだ改良点に基づいた結果を公開しなくても良い
ことになっています。
このことは、リチャード・ストールマンをはじめとするオープン・ソースの担い手達に言わせると、フリーソフトウェアではない
と言うことになり、ソフトウェアの自由に反する存在であるとなります。フリーソフトウェアには以下の自由が必要とされます(省
略しています)
。
プログラムを実行する自由 (第 0 の自由)。
ソースコードにアクセスする自由(第 1 の自由)。
コピーを再頒布する自由 (第 2 の自由)。
あなたの改良点を公衆に発表する自由 (第 3 の自由)。
第 1 の自由と第 3 の自由のためには、ソースコードが公開されていて、入手可能であることが前提条件です。
ストールマン達はこれらを称してコピーレフトと呼んでいます。コピーライトに引っ掛けたものでしょうが、レフトを持ってく
るあたり、ニヤリとさせるものがあります。
もっとも、ストールマン達が提唱する GPL(General Public License)はこうした理想を実現するための制限が大変厳しく、実際
のところ使いにくいものになってしまっていると言う意見も多いようです。
現状では、より制約のゆるい BSD ライセンスを元にしたライセンス体系へと移行するプロジェクトが増えているようでも有りま
す。
Linux のソースコードへのアクセスがマイクロソフト社のサイトからが最も多かったと言う話もありましたが、例えそれが違法
であったとしても、誰にも公言することなくオープン・ソースの成果を独占的な商用ソフトに利用することは可能です。
だとすれば、むやみと制限の厳しいライセンスを利用することで間口を狭めてしまうことは、結果的にオープン・ソース陣営の
広がりを阻害する可能性もあるわけです。
Firebird プロジェクトが、バージョン 1.5 で全てのコードを C から C++に書き換えようとしているのは、IPL からの離脱を目標
としているのだと思いますが、ライセンス問題で足を引っ張られるようなことが無いよう切に祈ります。
Delphi から利用する Firebird
Delphi データベースプログラミングスキーム
Delphi(Professional 版以上)からデータベースを利用するにはいくつもの手段が用意されています。そのうち、Delphi に付属する
もので、Firebird への接続に利用できるのは以下のようなものになります。
・
・
・
・
BDE(Borland Database Engine)
SQL-Link InterBase ドライバ
ODBC
dbGo(ADO Express)
ODBC
dbExpress
InterBase Express
この他にも IBObjects のような実績のある DB 接続コンポーネントがあります。Firebird プロジェクトの周辺でも Firebird Express
や ODBC ドライバなど、Firebird に接続するためのコンポーネントがいくつも開発されています。
BDE はこれまで最も多くの Delphi プログラマに利用されてきましたが、Delphi5 以降付属するようになった dbExpress への移行をボ
ーランドが進めていることも有り、海外では徐々にフェードアウトしているようです。
InterBase Express(IBX)も Delphi5 以降のバージョンに付属するようになったものですが、元になっている Free IB Components はそ
れ以前から使われてきています。InterBase 専用のコンポーネントと言うこともあり、細かいところまで制御できるようになっていま
す。InterBase のイベント通知機能などを使用するためには IBX を使用する必要があります。
dbGo については、マイクロソフトの MDAC のバージョンに影響され、一時動作しない状態に陥ったことも有り敬遠されていますが、
ADO 自体が高機能なこともあり、むやみと OS 廻りの Update をしないのであれば、これを利用することもいい選択肢だと思います。
本書では、BDE を利用して Paradox 等のファイル共有型データベースを利用していたユーザーの乗り換えを促すとともに、マイクロ
ソフト Access を利用してアプリケーションの開発をされているユーザーに、Delphi + Firebid への乗換えを促したいと思います。そ
のため、InterBase に特化してサービス API やイベントなどの制御が可能な代わりにトランザクション制御が複雑な InterBase Express
ではなく、dbExpress を利用して Firebird への接続を行います。この場合、現状の Firebird 1.0 では InterBase 6 とのほぼ 100%の交
換性があるため、ドライバとして InterBase 用のものを使用することにします。
また、dbExpress は BDE や ADO と違い、データをキャッシュして制御するなどの機能を持たない単方向データセットであるため、
TClientDataSet を利用して BDE と同等以上の機能を提供する方法を取ることとします。
dbExpress の概要
dbExpress は BDE の TTable や TQuery と違い、単方向のデータセットです。データベースのデータを全くバッファリングしないので、
カーソルの移動は First と Next しか出来ません。また、編集機能をサポートしないので、データコントロールを接続しても表示するこ
としか出来ません。
もし、TTable や TQuery のようにデータコントロールと接続して編集機能を利用したい場合は、TClientDataSet を利用することで可
能となります。
dbExpress によるデータベースへの接続は以下のような形態となります。BDE による接続と比較してみてください。
dbExpress では、TSQLConnection – TSQLDataSet – TDataSetProvidor – TClientDataSet – TDataSource – データコントロールとな
ります。
BDE では、TDatabase – TQuery – TDataSource – データコントロールですから、間に 2 つはさまった形になります。
レポーティング等には、単方向のデータセットで十分ですので、その場合には直接 TSQLDataSet を利用することになります。しかし、
TDBGrid を使ってデータを表示したい時などにはこのようにして、間に TClientDataSet を間に挟まないといけません。
dbExpress にはこの TSQLDataSet + TDataSetProvidor + TClientDataSet を 1 つにまとめた TSQLClientDataSet もありますが、内部
的に TDataSetProvidor と TClientDataSet を作成して利用しているため、これたの機能の全てを使うことが出来ません。面倒なようで
も、並べて使うのがいいようです。
また、TSQLQuery や TSQLTable などのコンポーネントもありますが、これらは従来の TQuery・TTable と同じように使えるようにカス
タマイズした TSQLDataSet なので、これまでのアプリケーションを移植する場合に最小限の変更で済むと言うメリットはありますが、
新規に作成する場合には TSQLDataSet を使うようにしたほうが良いでしょう。
(InterBase Express の TIBQuery や TIBTable などにも同
じことが言えます)
見積書アプリケーションの作成
では、前章で作成した Mitsumori.gdb に接続するアプリケーションを作成していきたいと思います。このアプリケーションでは、以
下のことが出来るようにします。
・
・
・
・
・
・
顧客マスタの追加・編集・削除
商品マスタの追加・編集・削除
見積基本情報の追加・編集・削除
見積明細情報の追加・編集・削除
各マスタの一覧印刷
見積書の印刷
今回のデータベースでは主キーをすべてトリガーによって設定するようにしたので、データの追加フォームと編集・削除のフォームは
別にします。必要なフォームは以下の通りです。
メ イ ン メ ニ ュ ー フ ォ ー ム
F_Main
顧客マスタの追加フォーム
顧客マスタの編集・削除フォーム
商品マスタの追加フォーム
商品マスタの編集・削除フォーム
見積基本情報の追加フォーム
見積基本情報の編集・削除フォーム
見積明細情報の追加フォーム
見積明細情報の編集・削除フォーム
顧客マスタの印刷レポート
商品マスタの印刷レポート
見積書の印刷レポート
データモジュール
F_Append_Cust
F_Update_Cust
F_Append_Prod
F_Update_Prod
F_Append_MitsuB
F_Update_MitsuB
F_Append_MitsuD
F_Update_MitsuD
F_Report_Cust
F_Report_Prod
F_Report_Mitsumori
DM_Main
まずはじめに、データモジュールを作成します。新規プロジェクトにデータモジュールを追加して、TSQLConnection を 1 つ追加しま
す。さらに、TSQLDataSet と TDataSetProvidor、TClientDataSet を 3 つ並べたものを 4 つ用意します。その他にも必要な TSQLDataSet、
TSQLSroredProc などを追加しました。
それぞれに、名前を付けていきます。TSQLConnection には CN_、TSQLDataSet には DST_、TDataSetProvidor には DSP_、TClientDataSet
には CDS_、TSQLStoredProc には SP_という接頭辞をつけるという命名規則をとりました。
データベース接続の設定
CN_Mitsumori をダブルクリックして接続ビルダを表示させます。
[+]ボタンをクリックして新規接続を追加します。ドライバ名に「Interbase」を選択し、接続名に「FB_Mitsumori」と入力して[OK]
ボタンをクリックします。右側の接続の設定でドライバの設定を以下のように変更します。
BlobSize=-1
CommitRetain=False
Database=d:\db\mitsumori.gdb
ErrorResourceFile=
LocaleCode=0000
Password=
RoleName=RoleName
ServerCharSet=SJIS_0208
SQLDialect=3
Interbase TransIsolation=ReadCommited
User_Name=sysdba
WaitOnLocks=True
変更したのは、Database・Password・ServerCharSet・SQLDialect の 4 つです。パスワードはログインプロンプトで入力しますから、
ここから削除しておきます。パスワードを埋め込むのはセキュリティ上問題ですが、自分しか使わないということであればここに書き
込んで、LoginPrompt を False にしてしまっても良いでしょう。
接続ビルダの[レ]ボタンをクリックして接続をテストして OK なら、接続ビルダを終了します。
接続ビルダを閉じると CN_Mitsumori の設定が次のように変更されています。
ここで追加した接続の内容はアプリケーションのプロジェクトではなく、dbExpress をセットアップしたフォルダ(デフォルトでは
C:Program Files\Common Files\Borland Shared\DBExpress)に作成される ini ファイル dbxconnections.ini へ保存されますので、
別のアプリケーションを作成する時にも利用できます。
各データセットの設定
次に TSQLDataSet の設定を行います。各 DST_hogehoge のプロパティで SQLConnection を CN_Mitsumori に指定します。ここで、
CommandText プロパティの右端のボタンをクリックすると、ログオンプロンプトが出てきますので、パスワードを入力して CommandText
の設定ダイアログを表示させます。
テーブル名や項目名をビジュアルに追加して SELECT 文を作成できますが、SQL コマンドが小文字だったりするので、ここは手で入力
した方が美しいですね。また、TClientDataSet からの Update の際にテーブル名が大文字になっていないと、テーブルが見つからない
と言うエラーが表示されるので、テーブル名・カラム名は全て大文字としておきましょう。(読み取りは出来るので、ちょっとバグくさ
い感じもします。)
※各オブジェクト(表・列)名に二重引用符を付けずにテーブルを作成するとが二重引用符でくくられた大文字に変換されます。Firebird
では、二重引用符でくくられたオブジェクト名はケースセンシティブになるので、大文字でないと通じないことになります。
Firebird は二重引用符をつけない SQL 文をすべて大文字に変換して実行します。ですから、SELECT 文が小文字でも実行できるのが正
しく、INSERT 文が小文字では実行出来ないはおかしいのです。
DST_Cust.CommnadText =
SELECT * FROM T_CUSTOMER
[OK]ボタンを押して、プロパティに SQL 文が設定されます。CommandText は TQuery の SQL プロパティと違い Stging 型のデータなの
で、改行は「・・」などと表示されてしまいますが、その辺は気にしないようにしましょう。
気をつけなくてはいけないのは、動的に SQL 文を設定する時に、SQL.Add('hogehoge')と同じようにして、以下のようにしてしまうこ
とです。
CommnadText := 'hogehoge' + 'foo bar';
このとき、文字列の前後に必ず空白を入れるようにしないと、SQL 文のエラーとなってしまうことがよくあります。以下のようにし
ておけば、安全です。
CommandText := ' hogehoge ' + ' foo bar ';
同様にして、以下の SQL 文を設定してしまいます。
DST_Prod.CommandText =
SELECT * FROM T_Product
DST_MitsuB.CommandText =
SELECT * FROM T_MITSUMORI_BASIC
DST_MitsuD.CommandText =
SELECT * FROM T_Mitsumori_Detail
DST_Cust_Insert.CommnadText =
INSERT INTO T_Customer
(Cust_Name,
Cust_Yomi,
Cust_Address1,
Cust_Address2,
Cust_Tel,
Cust_Fax,
Cust_Memo)
VALUES
(:P_Cust_Name,
:P_Cust_Yomi,
:P_Cust_Address1,
:P_Cust_Address2,
:P_Cust_Tel,
:P_Cust_Fax,
:P_Cust_Memo)
DST_Prod_Insert.CommandText =
INSERT INTO T_PRODUCT
(PRODUCT_NAME,
PRODUCT_YOMI,
UNIT_NAME,
UNIT_PRICE)
VALUES
(:P_PRODUCT_NAME,
:P_PRODUCT_YOMI,
:P_UNIT_NAME,
:P_UNIT_PRICE
)
DST_MitsuB_Insert.CommandText =
INSERT INTO T_Mitsumori_Basic
(CUST_ID,
MITSU_DATE,
MITSU_NAME,
MITSU_NO,
MITSU_YOMI
)
VALUES
(:P_CUST_ID,
:P_MITSU_DATE,
:P_MITSU_NAME,
:P_MITSU_NO,
:P_MITSU_YOMI
)
DST_MitsuB_List は動的に作成した CommandText を設定しますので、
ここでは空のままにしてコネクションだけを設定しておきます。
SP_MitsuD_Insert はデータベースに作成したストアドプロシージャーを実行するコンポーネントです。コネクション名を指定して、
一覧からストアドプロシージャーを選択します。
SP_MitsuD_Insert.StoredProcName = SP_INSERT_MITSU_D
プロシージャー名を設定すると、パラメーターも設定されるので、確認しておきましょう。
※ここでは使いませんでしたが、MS Access のクエリーだとテーブルの別名は[AS]をデフォルトで使用しますが、Firebird の場合、AS
を使用するとエラーになるので注意してください。
さて、TSQLDataSet の準備が出来たら、TDataSetProvidor をそれぞれ、以下のようにして各データセットに接続します。
DSP_Cust.DataSet =
DSP_Prod.DataSet =
DSP_MitsuB.DataSet
DSP_MitsuD.DataSet
DST_Customer
DST_Product
= DST_MitsuB
= DST_MitsuD
ここで各テーブルには主キーを設定してあるので、TDataSetProvidor の UpdateMode を upWhereKeyOnly にしておきましょう。こうす
ることで、TClientDataSet からの Update 要求に対して生成する SQL 文の Where 句が Where 主キー = hogehoge となります。
また、対応する TSQLDataSet の主キー項目で、ProviderFlags に pfInKey を設定してあげないといけません。TSQLDataSet を右クリッ
クして、[項目の設定]を実行し、
「項目エディタ」を使って[全ての項目を追加]しておきます。デフォルトでは、pfInUpdate と pfInWhere
が True になっているので、主キー項目だけを変更します。
同様に、対応する TClientDataSet にも静的項目を作成して、主キー項目の ProviderFlags に pfInKey = True を設定してください。
どちらか一方だけではうまく動作しませんでした。
最後に、TClientDataSet の ProvidorName プロパティをそれぞれ設定します。
CDS_Cust.ProvidorName =
CDS_Prot.ProvidorName =
CDS_MitsuB.ProvidorName
CDS_MitsuD.ProvidorName
DSP_Cust
DSP_Prod
= DSP_MitsuB
= DSP_MitsuD
さて、CN_Mitsumori にはデータベース名を設定してありますが、これでは後でデータベースの保存先を変更したりする時にリコンパ
イルしなくてはなりませんので、ini ファイルを使って設定を変更できるようにしておきます。
//データモジュール生成時の処理
procedure TDM_Main.DataModuleCreate(Sender: TObject);
var
ini:TIniFile;
begin
ini :=
TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
try
CN_Mitsumori.Params.Values['Database'] :=
ini.ReadString('Connection', 'Database' , 'D:\DB\MITSUMORI.GDB');
ini.WriteString('Connection', 'Database' ,
CN_Mitsumori.Params.Values['Database']); finally
ini.Free;
end;
end;
ini ファイルからの読み込みの後で、すぐ書き込んでいるのは、こうしておけばデフォルト値を記述した ini ファイルを用意しなく
ても済むからです。
調停ダイアログの追加
さて、ここで一つフォームを追加しなくてはいけません。IDE の[新規作成]-[その他]から、[ダイアログ]タブを表示させて、
「調停
ダイアログ」を選択肢、[OK]ボタンをクリックします。これは、TClientDataSet を利用した更新を実行した時に、リモートサーバーと
の間で更新に矛盾が生じた場合に表示されるダイアログボックスです。ユニットに Form_ReconcileError.pas 等と名前をつけて保存し
ておきます。
そして、データモジュールを表示させて、[ユニットを使う]メニューから、ReconcileErrorForm を追加します。その後で、各
TClientDataSet のイベント・OnReconcileError をダブルクリックして出来るコードに以下のように記述します。一つだけ記述したら、
後はドロップダウンから指定して共有しておきましょう。
procedure TDM_Main.CDS_CustReconcileError(DataSet: TCustomClientDataSet;
E: EReconcileError; UpdateKind: TUpdateKind;
var Action: TReconcileAction);
begin
Action :=
HandleReconcileError(DataSet,UpdateKind,E);
end;
メインフォームの作成
それでは、フォームの作成に進みます。まずは、メインメニューを作成します。大きさは Width=640、Height=480 の VGA サイズとし
ました。標準のフォントのままだと文字が小さくて見づらいので、Font.Size=11 としてあります。フォームの名前は、F_Main とし、ユ
ニットを Form_Main.pas として保存します。
ここではメインメニューがあって、各フォームをモーダル表示するスタイルでアプリケーションを作成します。モード付フォームは
もう古いという意見も聞きますが、業務系アプリケーションではまだまだ主流だと思いますし、誰でも簡単に使えると言う点では、す
ぐれたスタイルだと思っています。
メインメニューには追加系フォームの表示で 4 つ、編集系フォームの表示で 4 つのボタンを貼り付けます。さらに、ベベルの Height
を 2 に設定したもので区切って、下部に帳票印刷用のボタンを設定しました。これが 2 つあります。 ボタンのサイズはフォントを大
きくしたのにあわせて、それぞれ Width=240、Height=30 としました。
また、パネルを1つ配置して、Align=alBottom とし、最下部に配置したうえに、ボタンを一つ配置して「閉じる」ボタンとしました。
大きさは標準のままです。
継承元ベースフォームの作成
次に、各追加、編集用フォームの継承元となるフォームを作成します。フォームのサイズやフォント、
「閉じる」ボタンなど基本的な
機能を先に作成しておき、このフォームを継承することで、こうした作業は 1 回だけ行えばよいことになります。データの追加、変更、
削除などのメソッドも継承元フォームで実装するか、抽象メソッドとしておくことで、継承先のフォームでの作業を合理化することが
出来ます。
まずは、メニューから[新規作成]-[フォーム]を実行して、新しいフォームを追加します。フォームのサイズをメインフォームと同じ、
Width=640、Height=480 に設定し、Font.Size=11 としておきます。また、デザインを統一するため、下部にパネルを配置して、
「閉じる」
ボタンを追加しておきます。名前は F_Base として、ユニットを Form_Base.pas と言う名前で保存しておきます。
F_Base にはデータソースを一つ追加して、DS_Main という名前を付けておきます。この DS_Main に各フォームで利用する DataSet を
指定することで、各メソッドの記述を以下のように統一することが出来ます。そして、ベースフォームにおいて、具体的なデータセッ
トを指定することなく、DataSet に対する各基本メソッドの実装を行うとが出来るのです。
with DS_Main.DataSet do begin .. end;
また、下部のパネルに「追加」「更新」「削除」の各ボタンを配置しておきます。データベースへの操作は、簡単にいってしまえばこ
の 3 つしかありません。そして、これらのボタンのクリックイベントから呼び出すメソッドを以下のように実装します。
protected
{ Protected 宣言 }
procedure AppendRecord;virtual;
procedure UpdateRecord;virtual;
procedure DeleteRecord;virtual;
//レコードの追加処理
procedure TF_Base.AppendRecord;
begin
if (Assigned(DS_Main.DataSet) = True) then
begin
with DS_Main.DataSet do
begin
if (State <> dsBrowse) then Post;
Append;
end;
end;
end;
//レコードの更新処理
procedure TF_Base.UpdateRecord;
begin
if (Assigned(DS_Main.DataSet) = True) then
begin
with DS_Main.DataSet do
begin
try
if (State <> dsBrowse) then Post;
except
on EDBClient do
begin
ShowMessage(MSG_E_Update);
raise;
end;
end;
end;
end;
end;
//レコードの削除処理
procedure TF_Base.DeleteRecord;
begin
if (Assigned(DS_Main.DataSet) = True) and
(MessageDlg(MSG_A_Delete, mtWarning, mbOKCancel,0) = mrOk) then
DS_Main.DataSet.Delete;
end;
今回は、ベースフォームで各メソッドの基本形を実装していますが、ベースフォームでは abstract 指令を付加して抽象メソッドとし
ておいて、継承先でこれらの手続きを実装しても良いでしょう。また、その場合、各ボタンのクリックイベントハンドラでは以下のよ
うにしておきます。(実装していない機能を呼び出すようなことがあってはいけないわけですが、まあ念のためです。
)
Const
MSG_E_Abstract = 'この機能は実装されていません';
//追加ボタンのクリック処理
procedure TF_Base.BTN_AppendClick(Sender: TObject);
begin
try
AppendRecord;
except
on EAbstractError do
ShowMessage(MSG_E_Abstract);
end;
end;
Constants.pas と Globals.pas
さて、前述のようなエラーメッセージなどはユニットを追加して、全てまとめておくと後々のメンテナンスが楽になります。また、
万が一ローカライズをしなくてはならないといった時に、変更箇所がまとまっていないと大変な手間がかかることになります。
(まず無
いと思いますが)
定数、定数配列、型宣言などは Constants.pas というユニットを作成して、全てこれにまとめました。また、プロジェクトにグロー
バルな変数、関数などは同じく Globals.pas というユニットにまとめてあります。
顧客・商品追加フォーム
この 2 つのフォームでは、ラベルとエディットを配置して、追加ボタンから呼び出される AppendRecord 手続きの中で Insert 用の
TSQLDataSet にパラメータを設定して呼び出しているだけです。
このラベルとエディットを配置するのが一つ一つやると面倒なので、データモジュールから項目エディタを表示させて、ドラッグ・
ドロップでいっぺんに配置しました。こうすると、各項目に対応したラベルと TDBEdit、そしてデータソースが自動的に作成されます。
そこで、フォームを右クリックし[エディタで表示]を実行し、TDBEdit を TEdit に全て置換してしまいます。それから、DataSource
と DataField プロパティを全て削除してしまえば、一丁上がりです。コンテキストメニューから[フォームで表示]を実行してください。
データソースは削除してしまいましょう。
AppendRecord 手続きは、ベースフォームで virtual 指令をつけて protected 部で宣言してありますので、以下のようにして override
します。
protected
procedure AppendRecord;override;
こうしておけば、いったんインスタンスを作成したフォームのメソッドを外部から(TF_hogehoge as TF_Base).AppendRecord として
呼び出しても、TF_hogehoge の AppendRecord が呼び出されることが保証されます。継承先のフォームをたくさん作って、そのメソッド
を外部から呼ぶ可能性がある場合、こうしておけば隠れたバグを防ぐことが出来ます。今回は、全て protected のままですから、vritual
-> override としなくても特に問題はないでしょうが、念のため上記のようにしておきました。
また、この後の見積基本情報、詳細情報の追加フォームも同様ですが、
「更新」
「削除」ボタンの Visble プロパティを False にしてお
きます。継承元のフォームで追加したコンポーネントは削除できないので、必要の無いものはこうしておきます。
トム猫の独り言(3)
override と隠蔽
継承元のクラスで宣言された仮想メソッドを、override 指令を付けないで継承先クラスで最宣言すると、メソッドが隠蔽された状態
になります。
override と隠蔽の違いは、わかりにくいものですが、簡単に示すと以下のようになります。
override
コンストラクタが呼ばれたクラスのメソッドが実行される。
隠蔽
クラス型変数を定義したクラスのメソッドが実行される。
以下にサンプルのコンソールアプリケーションを示します。コンパイルして、コマンド
program Project1;
{$APPTYPE CONSOLE}
uses
プロンプトから実行してみてください。
SysUtils;
type
TClassA = Class(TObject)
procedure SayYes; virtual;
end;
TClassB = Class(TClassA)
procedure SayYes;reintroduce; //隠蔽
end;
TClassC = Class(TClassA)
procedure SayYes;override;
end;
procedure TClassA.SayYes;
begin
Writeln('Yes, I am TClassA');
end;
procedure TClassB.SayYes;
begin
Writeln('Yes, I am TClassB');
end;
procedure TClassC.SayYes;
begin
Writeln('Yes, I am TClassC');
end;
var
Obj1:TClassA;
Obj2:TClassA;
begin
{ TODO -oUser -cConsole Main : この下にコードを記述してください }
Obj1 := TClassB.Create;
Obj1.SayYes; //TClassA.SayYes が呼ばれる
Obj2 := TClassC.Create;
Obj2.SayYes; //TClassC.SayYes が呼ばれる
(Obj2 as TClassA).SayYes;
end.
実行した結果は、以下のようになります。
>Project1
Yes, I am TClassA
Yes, I am TClassC
Yes, I am TClassC
見積基本情報追加フォーム
見積基本情報の追加用フォームでは、日付の指定に TDateTimePicker を使用しています。また、顧客の指定にコンボボックスを使用
しました。顧客の一覧を表示させるために、フォームの生成時に以下のようにして、DM_Main で定義する Public な手続きを呼んでいま
す。
//フォームの生成時の処理
procedure TF_Append_MitsuB.FormCreate(Sender: TObject);
begin
inherited;
DM_Main.SetCustNameToCMB(CMB_Cust_Name);
end;
呼出先は以下のようになっています。
//顧客名をコンボボックスにリストアップする処理
procedure TDM_Main.SetCustNameToCMB(CMB: TComboBox);
begin
with CDS_Cust do
begin
Open;
try
First;
while (Eof = False) do
begin
CMB.Items.AddObject(
FieldByName('Cust_Name').AsString,
Pointer(FieldByName('Cust_ID').AsInteger));
Next;
end;
finally
Close;
end;
end;
end;
コンボボックスへの参照を渡して、AddObject メソッドを利用し、顧客名と顧客 ID をリストに取り込んでいます。TStrings 型のオブ
ジェクトである、TComboBox.Items には Object を登録する機能がありますが、これはポンインタ型ですので、Integer を Pointer にキ
ャストして格納してあります。
コンボボックスから、この ID を取り出す処理は Globals.pas に共通関数としてあります。後ほど見積基本情報を一覧に登録したり、
取り出したりしますので、こうしてあります。コンボボックス自体を拡張して、Integer 型として値を読み書き出来るように変更して
しまう方がより Delphi らしいのですが、ここでは簡単にするため上記のようにして有ります。
//コンボボックスの Objects を Integer として返す
function Get_intFromCMB(CMB: TComboBox): Integer;
begin
Result := 0;
try
Result :=
Integer(CMB.Items.Objects[CMB.ItemIndex]);
except
on EInvalidCast do
begin
ShowMessage(MSG_E_InvalidCast);
Exit;
end;
on EStringListError do
begin
ShowMessage(MSG_E_Cust_NotSelected);
Exit;
end;
end;
end;
データベースへの追加処理自体は、パラメータを設定して ExecSQL するだけです。
見積詳細情報の追加フォーム
見積詳細情報の追加フォームでは、見積基本情報が多数追加されている状況を考えて絞り込み機能を持たせることにしました。絞込
みは見積日付の範囲指定と顧客名での 2 通りとし、それぞれにチェックボックスを設けて必要な絞込みだけを可能にします。当然、ど
ちらのチェックもされていなければ、全ての基本情報をリストに列挙します。
このフォームでは、上記の手順でリストアップされた見積基本情報に対して、商品と数量を準じ追加していくことになります。その
ため、フォームを 3 つの部分に、ベベルを使って分けています。
フォームの生成時の処理で、先ほどと同様にして顧客名と商品名のコンボボックスを初期化しています。
//フォームの生成時処理
procedure TF_Append_MitsuD.FormCreate(Sender: TObject);
begin
inherited;
DM_Main.SetCustNameToCMB(CMB_Cust_Name);
DM_Main.SetProdNameToCMB(CMB_Product_Name);
end;
「見積基本情報呼出」ボタンのクリックイベントでは、以下のような処理を行って、コンボボックスへのリストアップを行っていま
す。
procedure TF_Append_MitsuD.BTN_MistuB_OpenClick(Sender: TObject);
var
intCust_ID:Integer;
begin
inherited;
//基本情報選択コンボボックスを初期化する
intCust_ID := 0;
if (CHKBOX_Cust.Checked = True) then
intCust_ID := Get_intFromCMB(CMB_Cust_Name);
DM_Main.SetMitsuBToCMB(CMB_MitsuB, CHKBOX_Date.Checked, CHKBOX_Cust.Checked,
DTP_Start.Date, DTP_End.Date, intCust_ID);
end;
Get_intFromCMB()関数は、先ほど使用したものです。顧客 ID を取得して、DM_Main の Public 手続きである、DM_Main.SetMitsuBToCMB()
手続きを呼んでいます。
DM_Main.SetMitsuBToCMB()関数は、与えられた引数に基づいて動的に SQL を生成し、コンボボックスに見積番号・顧客名・見積件名
と見積基本情報 ID を設定します。
少し長いですが、以下に示します。気をつけないといけないのは、TQuery.SQL プロパティと違って、CommandText プロパティは単な
るテキストであると言うことです。ですから、文字列を追加していく時には必ず前後に半角スペースを入れるようにしてください。以
下のようにするとエラーが出てしまいます。
CommandText := 'SELECT *' +
'FROM Table' +
'WHERE Key = 1';
SQL プロパティなら、TStrings ですから、Add()メソッドを利用して追加していくと、改行が自動的に入りますが、CommandText はそ
うでないことに注意してください。
//見積基本情報コンボボックスの初期化処理
procedure TDM_Main.SetMitsuBToCMB(CMB: TComboBox; bolDate,
bolCust: Boolean; dateStart, dateEnd: TDateTime; intCust_ID: Integer);
var
strWhereText:String;
begin
//基本情報選択コンボボックスを初期化する
if (CMB.Items.Count > 0 ) then CMB.Items.Clear;
CMB.ItemIndex := -1;
CMB.Text := '';
with (DST_MitsuB_List) do
begin
if (Active = True) then Close;
CommandText :=
' SELECT MB.MITSU_NO,MB.MITSU_NAME,MITSU_B_ID, C.CUST_NAME ' +
' FROM T_MITSUMORI_BASIC MB, T_CUSTOMER C ' +
' WHERE (MB.CUST_ID = C.CUST_ID) ';
//日付での絞込み条件指定
if (bolDate = True) then
begin
strWhereText :=
' AND (MITSU_DATE BETWEEN ' +
SQ + FormatDateTime('YYYY/MM/DD', dateStart) + SQ +
'
AND ' +
SQ + FormatDateTime('YYYY/MM/DD', dateEnd) + SQ + ')';
end;
//顧客での絞込み条件指定
if (bolCust = True) then
begin
strWhereText := strWhereText + ' AND ' +
' (C.CUST_ID = ' + IntToStr(intCust_ID) + ')';
end;
CommandText := CommandText + strWhereText;
Open;
try
First;
while (Eof = False) do
begin
try
CMB.Items.AddObject(
FieldByName('Mitsu_No').AsString +
':' + FieldByName('Mitsu_Name').AsString +
' <' + FieldByName('Cust_Name').AsString + '>',
Pointer(FieldByName('Mitsu_B_ID').AsInteger));
except
on EInvalidCast do
begin
ShowMessage(MSG_E_InvalidCast);
Exit;
end;
end;
Next;
end;
finally
Close;
end;
end;
end;
BETWEEN 句を指定しているところで、FormatDateTime()関数の結果を SQ で挟んでいることに注意してください。Access などでは、日
付型の指定に#を使って挟んでいますが、Firebird では日付を文字列として渡さないといけません。SQ は Constants.pas でシングルコ
ーテーションの別名として定義してありますので、これで挟み込んでやるとわかりやすくなります。
Const
SQ = ''''; //これでシングルコーテーションです
最後に、レコードの追加処理です。これは以下のように、ストアドプロシージャーにパラメータを渡して実行するだけですから、や
はり簡単です。
//見積明細情報のレコード追加処理
procedure TF_Append_MitsuD.AppendRecord;
var
intQunatity:Integer;
begin
with (DS_Main.DataSet as TSQLStoredProc) do
begin
try
if (CMB_MitsuB.ItemIndex = -1) then
raise Exception.Create(MSG_E_Mitsu_B_NotSelected)
else
ParamByName('P_Mitsu_B_ID').AsInteger:= Get_intFromCMB(CMB_MitsuB);
if (CMB_Product_Name.ItemIndex = -1) then
raise Exception.Create(MSG_E_Product_NotSelected)
else
ParamByName('P_Product_ID').AsInteger:= Get_intFromCMB(CMB_Product_Name);
try
intQunatity := StrToInt(EDT_Quantity.Text);
except
Exception.Create(MSG_E_Convert);
end;
ParamByName('P_Quantity').AsInteger := intQunatity;
ExecProc;
ShowMessage(MSG_S_INSERT);
EDT_Quantity.Clear;
CMB_Product_Name.ItemIndex := -1;
except
ShowMessage(MSG_E_INSERT);
Params.Clear;
Exit;
end;
end;
end;
それぞれ、見積基本情報・商品が選択されていなければエラー処理を行い、数量が Integer に変換できなければエラー処理を行うよ
うにしてあるだけで、パラメーターの設定・ExcecProc というのが本体の処理となっています。
顧客マスタの編集・削除フォーム
この 2 つは本当に簡単です。 DS_Main.DataSet にそれぞれ CDS_Cust・CDS_Prod を設定してあり、
フォームの生成時に DS_Main.DataSet
を Open して、フォームのクローズ時に Close するだけとなっています。
編集用のボタンは「追加」だけ、Visible を False にして、位置を入れ替えてあります。
また、レコードのナビゲーションが出来るように TDBNavigator を下部のパネルに配置してあります。VisibleButtons のうち、Insert・
Delete・Edit・Post は非表示としました。
見積基本情報の編集・削除フォーム
このフォームでは少しトリッキーなことをしています。フォームをベベルで区切って、日付範囲と顧客名で絞込みが出来るようにし
てあるのは、F_Append_MitsuD と同様です。
トリ ッキ ーな のは 、見 積日 付の表 示・ 変更を TDateTimePicker で行 うと ころ です 。Delphi 標準 のデ ータ コン トロ ール には
TDBDateTimePicker というのは存在しません。そこで、TDataTimePicker の上に TDBEdit をうまく載せてしまい、ドロップダウンのボタ
ンだけが出るようにしてあります。そして、TDateTimePicker の OnCloseUp イベントで TDBEdit へと日付を設定するようにしています。
//デートタイムピッカーの変更時の処理
procedure TF_Update_MitsuB.DTP_Mitsu_DateCloseUp(Sender: TObject);
begin
inherited;
DS_Main.DataSet.Edit;
DS_Main.DataSet.FieldByName('MITSU_DATE').AsDateTime := DTP_Mitsu_Date.Date;
end;
「追加」ボタンの Visible = False の設定と、位置の入れ替え、TDBNavigator の配置などは先ほどと同じようにしています。
見積詳細情報の編集・削除
さて、ここが最大の見せ場です。最終的な見積内容の確認・編集と見積書の印刷を実装します。ベベルで 3 つに区切って、絞込みと
見積基本情報の一覧をコンボボックスで表示するところまでは、F_Append_MitsuD と同様です。もう一段継承元フォームを作っても良
かったかもしれませんが、今回は 2 つだけなのでコピーで済ませました。
下部には TDBGrid を配置して、CDS_MitsuD の内容を表示するようにしました。TDBGrid で気をつけなくてはいけないなのは、参照項
目を設定しあるカラムでドロップダウンしてほしくないものの、ButtonStyle プロパティを cbsNone に設定しておくことです。
CDS_MitsuD には PRODUCT_NAME と UNIT_NAME の 2 つの参照項目を設定してあるので、この 2 つの TColumn のプロパティで、ButtonStyle
= cbsNone と設定しておきます。
また、見積の合計を計算するために、TClientDataSet の TAggregateField を使用しています。項目エディタで項目を新規作成し、
「項
目の種類」で「集合体」を選択すると項目エディタの下部が区切られて、新しい TAggregateField 型の項目が作成されます。
この SUM_PRICE 項目の Expression プロパティに SUM(UNIT_AMOUNT)と設定します。GroupingLevel と IndexName を指定すると、Index
にしたがって集計することが出来ますが、今回は元になる SQL でレコードを絞り込みますので、GroupingLevel = 0 で、IndexName は指
定しません。この集計項目を計算させるためには、Active プロパティを True に設定し、さらに CDS_MitsuD の AggregatesActive プロ
パティも True に設定しなくてはなりません。
この SUM_PRICE 項目を合計金額を示す TDBEdit に接続すると、グリッドに表示されているレコードの金額合計を自動的に表示するこ
とが出来ます。
ただし、今回使用した限りでは DisplayFormat で指定した形式文字列が機能しなかったため、項目の GetText イベントハンドラ内で
表示書式の設定を行わなくてはなりませんでした。
//見積詳細情報の合計金額表示用処理
procedure TDM_Main.CDS_MitsuDSUM_PRICEGetText(Sender: TField;
var Text: String; DisplayText: Boolean);
begin
if (Sender.FieldName = 'SUM_PRICE') then
begin
try
Text := FormatFloat('#,#', Sender.Value) + '
';
except
//例外の抑制
Text := '';
end;
end;
end;
また、このフォームで編集できるのは数量と単価のみとして、その他のカラムは ReadOnly を設定しました。商品名を変更すると、単
価を再設定しなくてはいけないなど処理が複雑になるため、新しい商品が必要ならば追加フォームで処理をします。
見積書の印刷
見積書の印刷には付属の QuickReport を使用しました。QuickReport は Professional 版以上にはずっと付属していますので、一度は
使ったことがあると思います。ビジュアルに帳票をデザインすることが可能で、TDataSet に接続してデータベースのレコードを印刷す
ることが可能なレポーティングソフトです。
見積書の基本情報については、データセットへの接続機能を使わないで、TQRLabel の Caption に書き込みました。
タイトル、カラムヘッダ、ディーテイル、サマリの各バンドに必要なコントロールを配置して、印刷ボタンのクリック処理から呼び
出すだけです。
//見積書印刷ボタンの処理
procedure TF_Update_MitsuD.Button1Click(Sender: TObject);
var
dblTax, dblSum_Price, dblSum_All:Double;
intMitsu_B_ID, intCust_ID:Integer;
begin
inherited;
if (Assigned(DS_Main.DataSet) = False) or
(DS_Main.DataSet.Active = False) then
begin
ShowMessage(MSG_E_Mitsu_D_NotOpened);
Exit;
end;
F_Report_Mitsumori := TF_Report_Mitsumori.Create(Self);
try
with F_Report_Mitsumori,DS_Main.DataSet do
begin
dblSum_Price := FieldByName('SUM_PRICE').AsVariant;
dblTax := Int(dblSum_Price * Tax_Rate);
dblSum_All := dblSum_Price + dblTax;
QRLBL_Sum_Price.Caption := FormatFloat('#,#', dblSum_Price);
QRLBL_Tax.Caption := FormatFloat('#,#', dblTax);
QRLBL_Sum_All.Caption := FormatFloat('#,#', dblSum_All);
QRLBL_Amout_Mony.Caption := '\ ' + FormatFloat('#,#', dblSum_All) + '.-';
intMitsu_B_ID := Get_intFromCMB(CMB_MitsuB);
DM_Main.CDS_CUST.Open;
try
with DM_Main.CDS_MitsuB do
begin
DM_Main.OpenMitsuB(CHKBOX_Date.Checked, CHKBOX_Cust.Checked,
DTP_Start.Date, DTP_End.Date, intCust_ID);
try
Locate('MITSU_B_ID', intMitsu_B_ID, []);
QRLBL_Mitsu_No.Caption := FieldByName('MITSU_NO').AsString;
QRLBL_Mitsu_Date.Caption :=
FormatDateTime('yyyy/mm/dd', FieldByName('MITSU_DATE').AsDateTime);
QRLBL_Mitsu_Name.Caption := FieldByName('MITSU_NAME').AsString;
QRLBL_Cust_Name.Caption := FieldByName('CUST_NAME').AsString + ' 様';
finally
Close;
end;
end;
QuickRep1.Preview;
finally
DM_Main.CDS_Cust.Close;
end;
end;
finally
F_Report_Mitsumori.Free;
end;
end;
このイベント処理の中では、消費税の計算と合計の算出、それぞれの QR ラベルへの設定などを行った後で、QuickRep1 の Preview メ
ソッドを呼び出しています。
顧客 、商品の各マ スタ一覧も、 QuickReport で簡 単に作成して、メ インフォーム のボタンから動 的のフォーム を生成して、
QuickRep1.Preview を実行しています。
以上、Firebird を利用した簡易見積アプリケーションの作成を行いましたが、dbExpress とデータコントロールのおかげで、ほとん
ど Firebird で有ると言うことを意識しないで終わると言う結果になりました。
Delphi におけるデータベースアプリケーション作成のスキームにおいて TDataSet と TDataSource の存在が、恐らくもっとも偉大な
発明なので はないかと思います。 すべてのデータベース 接続を抽象化す る TDataSet とデータコン トロールへの橋渡しを 行う
TDataSource が有ることで、データベースを意識しないアプリケーションプログラミングを行うことが出来るのです。