コンテンツ |
 |
|
|
 |
 |
著者 |
Connie Tsui
DB2ソリューション・インテグレーション・チーム
IBMトロント研究所
|
 |
|
|
| |
|
はじめに
JavaTMを使ってリレーショナル・データにアクセスするには、SQLJとJDBCTMという2つの標準的な方法があります。IBM®
DB2® Universal DatabaseTM(UDB)アプリケーションにはSQLJが適していると考えられているのはなぜでしょうか。それは、SQLJがすでにセキュリティー、パフォーマンス、簡素化を求めるアプリケーション・プログラマーに最適の言語となっているからです。この記事では、SQLJの背景に若干触れたあと、JDBCと比較したSQLJの利点について説明し、DB2
UDB Version 8.1が提供するSQLJの新しい機能および改善された機能を取り上げます。
SQLJの背景
1997年4月に、データベース・ベンダーは、Javaプログラミング言語に静的SQLステートメントおよびコンストラクトを使用する方法についてアイデアを交換するため、非公式のオープン・グループとして定期的に集合することを始めました。中心メンバーとなったのは、IBM、Oracle、Compaq、Informix®、Sybase、Cloudscape、Sun
Microsystemsなどでした。グループは、開発を進めていた仕様に、当初、JSQLという名前を付けていましたが、JSQLが登録商標名であることがわかったあと、JSQLからSQLJに変更しました。1997年12月、Oracleは、Javaへの組み込みSQLの基準実装を他のメンバーに提供しました。この基準実装は、JDK
1.1をサポートする任意のプラットフォーム上で動作可能であり、ベンダー中立でした。1998年12月、JavaへのSQL組み込みの仕様が完成し、ANSI規格「Database
Language - SQL, Part 10 Object Language Bindings(SQL/OLB)ANSI x3.135.10-1998」として受け入れられました。この仕様は一般に、SQLJ仕様のパート0と呼ばれています。現在は、SQL/OLB(Object
Language Bindings)として知られています。
SQLJ仕様は、現在、2つのパートで構成されています。
- SQL/OLB:JavaへのSQL組み込み
規格のこのパートは、JavaメソッドへのSQL組み込みの構文と意味、および生成したSQLJアプリケーションのバイナリー移植性を保証するメカニズムを説明しています。これがこの記事のトピックです。
- SQL/JRT:Javaプログラミング言語を使用するSQLルーチンと型
規格のこのパートは、下記について取り上げています。
- SQLストアード・プロシージャーとユーザー定義関数などのJava静的メソッドの呼び出しの仕様。SQLシステムへのJavaクラスのインストール、SQL関数やストアード・プロシージャーとしてのSQLでのJavaクラスの静的メソッドの呼び出し、指定したパラメーター出力値の取得、SQL結果セットの戻りのためのSQL拡張機能を定義しています。
- SQLユーザー定義データ型として、Javaクラスを使用するための仕様。SQLでデータ型としてJavaクラスを使用するためのSQL拡張機能を定義しています。
用語:この記事ではこれ以降、SQLJという用語は、SQL/OLBのみを意味します。
SQLJプログラミング環境
HSSFを使って、Excelファイルに各種の操作を加えることができます。この記事で説明するように、単に数値や文字列のセル値を書き込むことはもちろんですが、それだけでなく、行や列のサイズの定義、セルのスタイルの設定(テキストを太字や斜体にする、境界線を挿入する、など)といったことも可能です。
アプリケーションのインストールと実行
SQLJ環境には、開発とランタイムの2つのフェーズがあります。このセクションでは、各フェーズに関係するコンポーネントとそのコンポーネント間の関係について説明します。
SQLJアプリケーションの開発
SQLJを使用するアプリケーションを開発するには、変換プログラム、プロファイル・カスタマイザー、プロファイル・バインダーの3つのコンポーネントが必要です。この3つのコンポーネントをサポートする機能を提供するユーティリティーは、それぞれ、sqlj、db2sqljcustomize、db2sqljbindです。図1にこのプロセスの概要を示します。
- 最初に、SQLJ変換プログラム(sqlj)を呼び出し、SQLJソース・ファイルを読み込んで、プログラムのSQLJ構文に問題がないかをチェックします。エラーがなければ、Javaソース・ファイルと0個以上のSQLJプロファイルが生成され、オプションで、生成したJavaソースがバイト・コード(デフォルト)にコンパイルされます。SQLランタイムを呼び出してSQL操作を実行する組み込みSQLは、生成されたJavaソース・ファイルに置き換わります。
- 次に、SQLJプロファイル・カスタマイザー(db2sqljcustomize)を呼び出して、生成された直列化プロファイルに対応するDB2カスタマイズを作成します。カスタマイザーは、オプション(デフォルト)で、動的に作成可能なSQLステートメントにオンライン・チェックを実行します。このオンライン・チェックで、構文、意味、スキーマの検証が実行されます。また、オプション(デフォルト)で、SQLJプロファイル・バインダーを呼び出してDB2パッケージのバインドも行います。
- プロファイルのカスタマイズ時に自動バインドを実行しないようにした場合は、別途SQLJプロファイル・バインダー(db2sqljbind)を呼び出して、カスタマイズ済みのSQLJプロファイルをデータベースにバインドすることができます。
- カスタマイズされているかいないかにかかわらず、プロファイルの内容を確認するには、SQLJプロファイル・プリンター(db2sqljprint)を使って、プロファイルの内容をテキスト形式で出力することができます。
図1.SQLJ開発環境
SQLJアプリケーションの実行
SQLJランタイムは、JDBCドライバーを利用して、データベースへアクセスするためのデータベース接続を取得します。カスタマイズされていないSQLJアプリケーションは、任意のJDBC2.0ドライバーで実行可能です。カスタマイズされていないSQLJアプリケーションを実行するのは、開発時のテスト目的のみです。カスタマイズ済みのSQLJアプリケーションを実行するには、V8
CLIベースのJDBCタイプ2ドライバー、Universal JDBCドライバー(タイプ2またはタイプ4)を使って、データベース接続を確立することができます。このセクションでは、カスタマイズ済みSQLJアプリケーション用のランタイム環境についてのみ説明します。
SQLJアプリケーションを実行すると、SQLJランタイムが、カスタマイズ済みのプロファイルからSQL操作についての情報を読み取り、カスタマイズに格納されたパッケージ・キー情報(パッケージ名、パッケージ整合性トークン、コレクション名)に一致するDB2パッケージ内のステートメントを実行します。
図2.SQLJランタイム環境
JDBCと比較したSQLJの利点
SQLJとJDBCの仕様は両方とも、Javaを使ってリレーショナル・データベースへアクセスする方法を記述しています。このセクションでは、以下の側面から両者の相違を説明します。
表1は、これから説明するSQLJとJDBCの相違について要約したものです。
正常にログインできたら、図2に示すように、現在の接続で利用可能な表が入った画面が表示され、目的の表を選択することができます。
規格およびSQL仕様レベル
SQLJは、「ISO/IEC 9075-10:2000 Information technology -- Database languages
-- SQL -- Part 10: Object Language Bindings(SQL/OLB)」の実装です。SQLJは、J2EEプラットフォームの一部ではありません。
JDBCは、J2SE 1.4とJ2EE 1.4プラットフォーム仕様の必須コンポーネントです。Java Software Development
Kit(JDK)のバージョン1.1以降、JDKの中核部分となっています。java.sqlパッケージにも組み込まれています。JDBCドライバーは、なんらかの拡張を仕様に定義して、最低限Entry
SQL-92ステートメントをサポートしなければなりません。
セキュリティー
SQLJにセキュリティー許可モデルが実装されていることが、ユーザーがSQLJの使用を検討する最大の理由です。静的SQLでは、セキュリティー特権がパッケージ作成者に割り当てられ、DB2パッケージに格納されます。
カスタマイズされたDB2 SQLJでは、SQLは静的に実行されます。したがって、SQLステートメントはパッケージ所有者の特権を使って実行されます。SQLJアプリケーションを実行する他のすべてのユーザーについては、パッケージにEXECUTE特権を付ける必要があります。つまり、適切な特権が明示的に与えられていない限り、プログラム実行の許可を与えられているユーザーが、必ずしも、プログラムが照会する、あるいは変更しようとしているテーブルまたはビューに対して、SELECT、UPDATE、DELETE、INSERTの権利を持っているわけではありません。
これに対して、JDBCアプリケーションのSQLステートメントは、データベースに接続しアプリケーションを実行するユーザーの特権によって実行されます。したがって、ユーザーには、テーブルにアクセスする特権が必要です。
パフォーマンス
SQLJで、SQLステートメントをJavaプログラムに組み込みできるのは、SQL-92で、C、COBOL、FORTRANその他のプログラミング言語にSQLステートメントを組み込みできるのに似ていますが、SQLJアプリケーションは、SQLJプロファイルのカスタマイズの有無に応じて、動的または静的に実行することが可能です。SQLJアプリケーションはプリコンパイルされ、SQLステートメントのパス長さは、パッケージがDB2データベースに格納される際に最適化されます。静的に実行されるSQLJアプリケーションは、JDBCよりも優れたパフォーマンスをもたらすことができます。
ここで推奨している静的実行を利用したい場合は、SQLJプロファイル・カスタマイザーを使ってプロファイルをカスタマイズすることが必要です。
JDBCでは、SQLステートメントは動的に実行されます。構文または意味エラーによる例外があれば、アプリケーション実行時に発生します。
静的または動的SQLステートメント処理は、DB2 UDBモニターを使って検証することができます。2つの監視方法として、スナップショット監視とイベント監視があります。スナップショット・モニターは、特定時点のデータベース・アクティビティーに関する情報を提供します。イベント・モニターは、DB2
UDBイベントの特定マイルストーンの発生を記録します。下記のリスト1は、JDBCプログラムから生成されたイベント・モニターの出力サンプルの抜粋です。「Type:
Dynamic」は、SELECT job FROM staff WHERE name = ?ステートメントが動的に実行されたことを伝えています。
リスト1 JDBCプログラムから生成されたイベント・モニターの出力サンプル
| |
10) Statement Event ...
Appl Handle: 23
Appl Id: G91AA377.G576.00F306261BF2
Appl Seq number: 0001
Record is the result of a flush: FALSE
-------------------------------------------
Type : Dynamic
Operation: Prepare
Section : 1
Creator : NULLID
Package : SYSSH200
Consistency Token : SYSLVL01
Package Version ID :
Cursor : SQL_CURSH200C1
Cursor was blocking: FALSE
Text : SELECT job FROM staff WHERE name = ?
|
リスト2は、SQLJプログラムから生成されたイベント・モニターの出力サンプルの抜粋です。出力中の「Type: Static」と「Package:
SRQT402」は、ステートメントがSRQT402パッケージに対して静的に実行されたことを伝えています。
リスト2.SQLJプログラムから生成されたイベント・モニターの出力サンプル
| |
10) Statement Event ...
Appl Handle: 12
Appl Id: G91ABD18.G47D.00F306C01D63
Appl Seq number: 0001
Record is the result of a flush: FALSE
-------------------------------------------
Type : Static
Operation: Execute
Section : 1
Creator : NULLID
Package : SRQT402
Consistency Token : SARoQCAp
Package Version ID :
Cursor :
Cursor was blocking: FALSE
|
注:いくつかのステートメントは、カスタマイズされたSQLJプログラムでは正常に実行されますが、カスタマイズされていないSQLJプログラムでは正常に実行されません。一例として、両方向スクロール・カーソル上のUPDATE/DELETE
WHERE CURRENT OFがあります。一般に、基礎となるJDBCドライバーにサポートされていない機能がある場合、カスタマイズされていないSQLJプログラムではその機能はサポートされません。
パフォーマンスのヒント:
singleton select照会では、SQLJが提供するSELECT INTO構文を使用することにより、大きなJDBC ResultSetsを任意に操作するときと比較して、ネットワーク・アクティビティーを軽減することができます。
図3は、singleton select照会のSQLJとJDBC構文を比較しています。
図3.単一行の検索−SQLJ対JDBC
| |
|
SQLJ syntax:
#sql [conCtx] { SELECT job INTO :job FROM staff WHERE name =
:name };
JDBC syntax:
PreparedStatement pstmt = con.prepareStatement(
"SELECT job FROM staff WHERE name = ? FETCH FIRST 1 ROW ONLY" );
ResultSet rs = pstmt.executeQuery();
if ( rs.next() )
job = rs.getString(1);
else
job = null;
pstmt.close();
|
構文
図3を見ると、JDBCよりもSQLJ構文が単純であることがわかります。多くのJava開発者にとって、この単純さは魅力的です。一般に、SQLJモジュールは、JDBCモジュールよりも簡潔で、書き方も容易です。これは、開発サイクルが短く、開発コストや保守コストが低くなることを意味します。図4は、SQLJで、単一行データをデータベースに挿入するのがいかに簡単であるかを示しています。他の言語(CやCOBOLなど)で書いた既存の組み込みSQLアプリケーションがある場合は、SQLJを使ってアプリケーションを簡単にJavaに移行することができます。
図4.単一行の挿入 − SQLJ対JDBC
SQLJ構文:
| |
|
sql [conCtx] { INSERT INTO sales VALUES(:date, :salesperson,
:region, :sales) };
|
JDBC構文:
| |
PreparedStatement pstmt = con.prepareStatement( "INSERT INTO sales VALUES (?, ?, ?, ?)" );
// set input parameter
pstmt.setObject(1, date);
pstmt.setString(2, salesperson);
pstmt.setString(3, region);
pstmt.setInteger(4, sales);
pstmt.executeUpdate();
pstmt.close();
|
SQLJとJDBCの相互運用性
SQLJ言語を使って、SQLJアプリケーションにJDBCステートメントを組み込むことができます。JDBCとSQLJ間のインタラクションを円滑にするため、SQLJには、同じアプリケーション内でSQLJ接続とJDBC接続間を共有し、SQLJイテレーターからJDBC結果セットを取得する方法、またはその逆の方法が用意されています。
SQLJアプリケーション内でJDBCを使用する必要があるのはどのようなときか
動的な操作、つまり、プログラムを作成する時点でSQL操作が不明な場合に、JDBCが必要です。リスト3は、JDBCを使ってSQLJプログラム内で動的照会(WHERE文節での名前は開発時点で不明)を実行する方法と、JDBCの結果セットをSQLJイテレーターに変える方法を示しています。
SQLJと異なり、JDBCはSQLJ構文を認識しません。また、SQLステートメントをJDBCアプリケーションに組み込むことはできません。
リスト3.JDBC結果セットからSQLJイテレーターへの変換
| |
Public class ResultSetInterop
{
#sql public static iterator Employees (String name, double salary);
public static void main(String[] argv) throws SQLException
{
// the code for creating the SQLJ connection context (conCtx) and
// the Connection object (con) is omitted
// create a JDBC statement object to execute a dynamic query
Statement stmt = con.createStatement();
String query = "SELECT name, salary FROM staff WHERE ";
query += argv[0];
ResultSet rs = stmt.executeQuery(query);
Employees SalReport;
// turn a JDBC result set to an SQLJ interator using the CAST statement
#sql [conCtx] SalReport = { CAST :rs };
while (SalReport.next()) {
System.out.println( SalReport.name() + " earns " + SalReport.salary() );
}
SalReport.close();
stmt.close();
} }
|
型チェックとスキーマ・チェック
SQLJは、Javaと同様に型指定の厳密な言語です。SQLJソース・ファイルからJavaソース・ファイルへの変換時に、SQLJ変換プログラムによりSQLJ構文がチェックされます。これは、他のDB2プリコンパイラーと同様です。また、Javaコンパイル時の変換フェーズでイテレーター・データ型変換が実行されます。たとえば、Javaコンパイラーは、(従業員給与などの)double型のイテレーター列がdouble型が許容されていない場所で使用されるのを防ぎます。したがって、String
hv = employees.salary() の代入は、コンパイル時にエラーを生成します。また、プロファイルのカスタマイズ時にオンライン・チェックが実行されるので、プログラミング・エラーを早期にキャッチすることができます。
JDBCには、ランタイム前に構文または意味チェックを実行する機能はありません。構文または意味エラーによる例外があれば、アプリケーション実行時に発生します。
注:
- オンライン・チェックは、従来のリリースでは変換フェーズで実行されていましたが、Version 8.1では、プロファイルのカスタマイズ時に実行されます。
- ランタイムまでキャッチされないSQLJエラーがあります。また、動的に作成できないステートメントもオンライン・チェックされません。
相違点の要約
表1は、SQLJとJDBCの相違点を要約したものです。
表1.SQLJとJDBCの比較
| |
SQLJ |
JDBC |
| 規格 |
ISO/ANSI(J2EEの一部ではない) |
Sun (part of J2EE) |
| SQL仕様レベル |
SQL-1999 |
なし(最低限、Entry Level SQL-92のサポートが必要) |
| セキュリティー |
強力 |
平均 |
| パフォーマンス |
高速(開発時に静的アクセス・プランを作成 |
低速(アプリケーション・プログラム実行時に動的アクセス・プランを作成) |
| 構文 |
高(簡潔) |
低(煩雑) |
| SQLJとJDBCの相互運用性 |
あり |
なし |
| 型チェックとスキーマ・チェック |
厳密(開発時に実行) |
緩やか(ランタイム時に実行) |
Version 8.1の新しい特長
DB2 UDB Version 8.1には、新しい機能を搭載した新設計のSQLJドライバーが同梱されています。新しいSQLJドライバーは、分散リレーショナル・データベース体系TM(DRDAR)として知られるオープン分散プロトコルに基づいています。これをサポートするCLIベースのJDBCドライバー(タイプ2とタイプ3)、および新しいUniversal
JDBCドライバー(タイプ2とタイプ4)がV8.1に採用されています。
SQLJの主な拡張は、次のように要約することができます。
新しいSQLJユーティリティーとランタイム
DB2 UDB Version 8.1のSQLJは、Pure Java SQLJユーティリティーとランタイム、および新しいオプションとオプション形式を実装しています。新しいランタイムにより、パフォーマンスはVersion
7に比べて格段に優れています。
Version 8.1では、SQLJ変換プログラムのsqljは、デフォルトで常に、生成されたJavaソースをコンパイルします。Version
7では、一部のJDKについてコンパイル・オプションが有効に使えず、手動でJavaファイルをコンパイルする必要がありました。
Version 8.1の新しいプロファイル・プリンターであるdb2sqljprintでは、開発者がURLを指定する必要がなくなりました。また、DB2ステートメント・タイプ、セクション番号、DB2結果セット・メタデータ情報など、実行するSQLステートメントに関する詳細な情報が提供されます。
プラットフォーム固有ファイルの解消
Version 8.1のSQLJプロファイル・カスタマイザーは、新しい直列化プロファイル形式を採用しており、DBRMファイルとバインド・ファイル(.bndファイル)の使用を解消しています。新しい形式は、すべてのプラットフォームに完全に移植可能です。すべてのBIND操作について、必要な情報のすべてが格納されており、ユーザーは、ターゲット・システム(UNIX®、Windows®、OS/390
、z/OSTM)上で直列化プロファイルを再カスタマイズする必要なく、任意のサーバー・プラットフォーム上で展開することができます。
Version 8の新機能
DB2 UDB V8.1の主な新機能には、次が含まれています。
DataSourcesを使った、SQLJ接続コンテキストの作成
Version 8.1 SQLJでは、SQLJ接続の作成用にJDBC DataSourceインタフェースを使用することができます。また、デフォルトの接続コンテキスト用の実装も変更されています。デフォルトの接続コンテキストを取得するために、SQLJランタイムは、jdbc/defaultDataSourceにJNDI検索を行います。何も登録されていない場合は、ドライバーがコンテキストにアクセスを試みたときに、nullコンテキスト例外がスローされます。したがって、JNDIにjdbc/defaultDataSourceを登録するか、または、DefaultContext.setDefaultContext(userctxt)を呼び出して、デフォルトのコンテキストを設定する必要があります。
推奨:SQLJ文節では明示的な接続コンテキストを使用してください。
リスト4.DataSourcesを使った、SQLJ接続コンテキストの作成
| |
// Create connection context class Ctx with the new dataSource keyword
#sql public static context Ctx with (dataSource="jdbc/sampledb");
String userid, password;
String empname;
// Create connection context object conCtx for the connection to jdbc/sampledb
Ctx conCtx = new Ctx(userid, password);
#sql [conCtx] { SELECT lastname INTO :empname FROM emp WHERE empno = '000010' };
conCtx.close();
|
スクロール可能イテレーター
スクロール可能イテレーターを使って、前方、後方、特定行への移動ができます。JDBCの両方向スクロール・カーソルと同様に、非センシティブまたはセンシティブのどちらもあります。
- 非センシティブ・イテレーターでは、イテレーターを開いたあと、基礎テーブルへの変更がイテレーターには見えません。非センシティブ・イテレーターは読み取り専用です。
- センシティブ・イテレーターでは、イテレーターまたは他のプロセスにより基礎テーブルに加えられた変更がイテレーターに見えます。たとえば、リスト5のコードは、名前付きイテレーターを使って、従業員テーブルのすべての行から逆順で従業員番号と姓を検索する方法を示しています。
リスト5.スクロール可能イテレーターの使い方
| |
// Declare a scrollable iterator.
#sql iterator ScrollIter implements sqlj.runtime.Scrollable with (sensitivity = SENSITIVE)
(String EmpNo, String LastName);
{
ScrollIter scrlIter;
#sql [conCtx] scrlIter={ SELECT empno, lastname FROM emp };
scrlIter.afterLast();
while (scrlIter.previous())
{
System.out.println(scrlIter.EmpNo() + " " + scrlIter.LastName());
}
scrlIter.close();
}
|
バッチ・アップデート
バッチ・アップデートを通じてステートメントをグループ化し、単一ラウンド・トリップを使って、実行用にバッチとしてデータベースに送ることができます。バッチ・アップデートには次のタイプのステートメントを含めることができます。
- 検索されたINSERT、UPDATEまたはDELETEステートメント
- CREATE、ALTER、DROP、GRANTまたはREVOKEステートメント
- 入力パラメーターのみのCALLステートメント
JDBCと異なり、SQLJでは、入力パラメーターまたはホスト式を含むステートメントの入った異種バッチに対応します。したがって、同じステートメント、異なるステートメント、入力パラメーターまたはホスト式を含むステートメント、入力パラメーターまたはホスト式が含まれないステートメントのインスタンスを同じSQLJステートメント・バッチに結合することができます。
推奨:
バッチをオフにする前に、または効率の悪いbatchモードがオンになったExecutionContextの使用を終了する前に、明示的にexecuteBatch()
を呼び出てください。これにより、バッチに含まれているすべてのステートメントが確実に実行されることになります。
リスト6のコード・フラグメントは、バッチでアップデートを実行することにより、すべてのマネージャーの給与を上げる方法を示しています。
リスト6.バッチ・アップデートの実行
| |
#sql iterator getMgr(String);
{
getMgr deptIter;
String mgrnum = null;
int raise = 400;
int currentSalary;
String url = null, username = null, password = null;
testContext conCtx = new testContext (url, username, password, false);
// Acquire execution context.
// All statements that execute in a batch must use this execution context.
ExecutionContext exeCtx = new ExecutionContext();
// Invoke ExecutionContext.setBatching (true) to create a batch.
exeCtx.setBatching(true);
#sql [conCtx] deptIter = { SELECT mgrno FROM dept };
#sql {FETCH :deptIter INTO :mgrnum};
while (!deptIter.endFetch())
{
#sql [conCtx] {
SELECT SALARY INTO :currentSalary FROM emp WHERE empno = :mgrnum};
#sql [conCtx, exeCtx]
{ UPDATE emp SET SALARY = :(currentSalary+raise) WHERE empno =:mgrnum };
#sql { FETCH :deptIter INTO :mgrnum };
}
exeCtx.executeBatch();
exeCtx.setBatching(false);
#sql [conCtx] {COMMIT};
deptIter.close();
exeCtx.close();
conCtx.close();
}
|
要約
SQLJのDB2実装は、JDBCと比較して明確な利点を提供します。より単純な構文、プリコンパイル時の型チェックとスキーマ・チェックは、開発コストを大きく引き下げます。また、SQLJアプリケーションにJDBCステートメントを組み込むための柔軟性もあります。これは、単一のアプリケーションが、SQLJとJDBCの両方の利点を活用できることを意味します。セキュリティーとパフォーマンスがJavaアプリケーションに重要である場合は、SQLJが正しい選択です。
詳細情報
著者について
 |
Connie Tsuiは、IBMトロント研究所のDB2ソリューション・インテグレーション・チームに勤めるスタッフ・ソフトウェア・アナリストです。トロント大学でコンピューター・サイエンスの学士号を取得しました。現在の中心テーマは、DB2とWebSphere®のインテグレーションです。
|
DB2、DB2 Universal Database、分散リレーショナル・データベース体系、DRDA、IBM、Informix、OS/390、WebSphereおよびz/OSは、IBM
Corporationの米国またはその他の国(あるいはその両方)における商標または登録商標です。
Windowsは、Microsoft Corporationの米国またはその他の国(あるいはその両方)における登録商標です。
JavaおよびすべてのJava関連の商標およびロゴは、Sun Microsystems, Inc.の米国またはその他の国(あるいはその両方)における商標または登録商標です。
UNIXは、The Open Groupの米国およびその他の国における登録商標です。
他の会社名、製品名、およびサービス名は、他社の商標またはサービスマークである場合があります
IBMの著作権および商標情報
原文はこちら
|