001/*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.hayabusa.db;
017
018import java.sql.DatabaseMetaData ;
019import java.sql.Connection;
020import java.sql.ResultSet;
021import java.sql.SQLException;
022
023import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
024import org.opengion.hayabusa.common.HybsSystemException;
025import org.opengion.hayabusa.resource.ResourceManager;
026import org.opengion.fukurou.db.ConnectionFactory;
027import org.opengion.fukurou.db.ResultSetValue;                          // 6.0.4.0 (2014/11/28)
028import org.opengion.fukurou.db.ApplicationInfo;
029
030/**
031 * 【検索】DatabaseMetaData の情報を検索するタグです。
032 *
033 * データベースに関する包括的な情報を提供する、DatabaseMetaData の内容を
034 * 表示する、タグです。テスト的に使用します。
035 *
036 * @og.formSample
037 * ●形式:
038 *       ・<og:databaseMetaData />
039 * ●body:なし
040 *
041 * ●使用例
042 *       <og:databaseMetaData />
043 *
044 * @og.group テーブル管理
045 *
046 * @version  4.0
047 * @author       Kazuhiko Hasegawa
048 * @since    JDK5.0,
049 */
050public class DBMetaData {
051        private String                  dbid            ;
052        private ResourceManager resource        ;
053        private ApplicationInfo appInfo         ;       // 3.8.7.0 (2006/12/15)
054
055        /**
056         * デフォルトコンストラクター
057         *
058         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
059         */
060        public DBMetaData() { super(); }                // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
061
062        /**
063         * DatabaseMetaData を作成する時のDB接続IDを指定します。
064         *
065         * @param       id データベース接続ID
066         */
067        public void setDbid( final String id ) {
068                dbid = id;
069        }
070
071        /**
072         * リソースマネージャーをセットします。
073         * リソースマネージャーが設定されていない、または、所定のキーの DBColumn が
074         * リソースに存在しない場合は、デフォルトの DBColumn オブジェクトを作成します。
075         *
076         * @param       resource リソースマネージャー
077         */
078        public void setResourceManager( final ResourceManager resource ) {
079                this.resource = resource;
080        }
081
082        /**
083         * アクセスログ取得の為、ApplicationInfoオブジェクトを設定します。
084         *
085         * @og.rev 3.8.7.0 (2006/12/15) 新規追加
086         *
087         * @param   appInfo アプリ情報オブジェクト
088         */
089        public void setApplicationInfo( final ApplicationInfo appInfo ) {
090                this.appInfo = appInfo;
091        }
092
093        /**
094         * ResultSet より、DBTableModel を作成して返します。
095         *
096         * @og.rev 6.0.4.0 (2014/11/28) SQLException を throws するように変更。
097         * @og.rev 6.0.4.0 (2014/11/28) ResultSetValue を使用するように変更。
098         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
099         *
100         * @param       resultSet ResultSetオブジェクト
101         *
102         * @return      作成された DBTableModelオブジェクト
103         * @throws      java.sql.SQLException データベース・アクセス・エラーが発生した場合
104         */
105        private DBTableModel makeDBTableModel( final ResultSet resultSet ) throws SQLException {
106
107                final ResultSetValue rsv = new ResultSetValue( resultSet );
108
109                final int clmSize =  rsv.getColumnCount();
110
111                final DBTableModel table = DBTableModelUtil.newDBTable() ;
112                table.init( clmSize );
113
114                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
115                if( resource == null ) {
116                        final String errMsg = "#setResourceManager(ResourceManager)を先に実行しておいてください。" ;
117                        throw new OgRuntimeException( errMsg );
118                }
119
120                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
121                final String[] names = rsv.getNames();
122                for( int clmNo=0; clmNo<clmSize; clmNo++ ) {
123                        final DBColumn clm = resource.makeDBColumn( names[clmNo] );
124                        table.setDBColumn( clmNo,clm );
125                }
126
127                // データ部の設定
128                while( rsv.next() ) {
129                        table.addColumnValues( rsv.getValues() ) ;
130                }
131                return table ;
132        }
133
134        /**
135         * このデータベースで使用可能なスキーマ名を取得します。
136         * 結果はスキーマ名で順序付けられます。
137         * スキーマ列は次のようになります。
138         *
139         * ・<b>TABLE_SCHEM</b> String ⇒ スキーマ名
140         * ・<b>TABLE_CATALOG</b> String ⇒ カタログ名 (null の可能性がある)
141         *
142         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定
143         *
144         * @return      スキーマ名をDBTableModelオブジェクトにラップ
145         * @see java.sql.DatabaseMetaData#getSchemas()
146         */
147        public DBTableModel getSchemas() {
148                final DBTableModel table ;
149                Connection conn = null ;
150                try {
151                        conn = ConnectionFactory.connection( dbid,appInfo );
152                        final DatabaseMetaData metaData = conn.getMetaData();
153                        // ====== table 求めの個所のみ、異なります。
154                        table = makeDBTableModel( metaData.getSchemas() );
155                        // ====== ここまで
156                }
157                catch( final SQLException ex) {
158                        ConnectionFactory.remove( conn,dbid );
159                        conn = null;
160                        throw new HybsSystemException( ex );
161                }
162                finally {
163                        ConnectionFactory.close( conn,dbid );
164                }
165                return table ;
166        }
167
168        /**
169         * 指定されたカタログで使用可能なテーブルに関する記述を取得します。
170         * カタログ、スキーマ、テーブル名および型の条件に一致するテーブルの記述だけが返されます。
171         * それらは、TABLE_TYPE、TABLE_SCHEM、TABLE_NAME によって順序付けられます。
172         *
173         * 各テーブルの記述には次の列があります。
174         *
175         * ・<b>TABLE_CAT</b> String ⇒ テーブルカタログ (null の可能性がある)
176         * ・<b>TABLE_SCHEM</b> String ⇒ テーブルスキーマ (null の可能性がある)
177         * ・<b>TABLE_NAME</b> String ⇒ テーブル名
178         * ・<b>TABLE_TYPE</b> String ⇒ テーブルの型。典型的な型は、"TABLE"、"VIEW"、"SYSTEM TABLE"、"GLOBAL TEMPORARY"、"LOCAL TEMPORARY"、"ALIAS"、"SYNONYM" である
179         * ・<b>REMARKS</b> String ⇒ テーブルに関する説明
180         * ・<b>TYPE_CAT</b> String ⇒ の型のカタログ (null の可能性がある)
181         * ・<b>TYPE_SCHEM</b> String ⇒ の型のスキーマ (null の可能性がある)
182         * ・<b>TYPE_NAME</b> String ⇒ の型名 (null の可能性がある)
183         * ・<b>SELF_REFERENCING_COL_NAME</b> String ⇒ 型付きテーブルの指定された「識別子」列の名前 (null の可能性がある)
184         * ・<b>REF_GENERATION</b> String ⇒ SELF_REFERENCING_COL_NAME の値の作成方法を指定する。値は、"SYSTEM"、"USER"、"DERIVED" (null の可能性がある)
185         *
186         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定
187         *
188         * @param       catalog カタログ名。(カタログ名と一致、"" はカタログなし、null は、カタログ名無条件)
189         * @param       schema  スキーマ名パターン。(スキーマ名と一致、"" はスキーマなし、null は、スキーマ名無条件)
190         * @param       tableName       テーブル名パターン。
191         *
192         * @return      テーブルに関する記述をDBTableModelオブジェクトにラップ
193         * @see java.sql.DatabaseMetaData#getSchemas()
194         */
195        public DBTableModel getTables( final String catalog,
196                                                                        final String schema,
197                                                                        final String tableName ) {
198                final DBTableModel table ;
199                Connection conn = null ;
200                try {
201                        conn = ConnectionFactory.connection( dbid,appInfo );
202                        final DatabaseMetaData metaData = conn.getMetaData();
203                        // ====== table 求めの個所のみ、異なります。
204                        // types String[] 組み込むテーブルの型のリスト。null はすべての型を返す
205                        table = makeDBTableModel( metaData.getTables(catalog, schema, tableName, null) );
206                        // ====== ここまで
207                }
208                catch( final SQLException ex) {
209                        ConnectionFactory.remove( conn,dbid );
210                        conn = null;
211                        throw new HybsSystemException( ex );
212                }
213                finally {
214                        ConnectionFactory.close( conn,dbid );
215                }
216                return table ;
217        }
218
219        /**
220         * 指定されたカタログで使用可能なテーブル列の記述を取得します。
221         * カタログ、スキーマ、テーブル名、および列名の条件に一致する列の
222         * 記述だけが返されます。
223         * それらは、TABLE_SCHEM、TABLE_NAME、ORDINAL_POSITION によって順序付けられます。
224         * 各列の説明を次にします
225         *
226         * ・<b>TABLE_CAT</b> String ⇒ テーブルカタログ (null の可能性がある)
227         * ・<b>TABLE_SCHEM</b> String ⇒ テーブルスキーマ (null の可能性がある)
228         * ・<b>TABLE_NAME</b> String ⇒ テーブル名
229         * ・<b>COLUMN_NAME</b> String ⇒ 列名
230         * ・<b>DATA_TYPE</b> short ⇒ java.sql.Types からの SQL の型
231         * ・<b>TYPE_NAME</b> String ⇒ データソース依存の型名。UDT の場合、型名は完全指定
232         * ・<b>COLUMN_SIZE</b> int ⇒ 列サイズ。char や date の型については最大文字数、numeric や decimal の型については精度
233         * ・<b>BUFFER_LENGTH</b> - 未使用
234         * ・<b>DECIMAL_DIGITS</b> int ⇒ 小数点以下の桁数
235         * ・<b>NUM_PREC_RADIX</b> int ⇒ 基数 (通常は、10 または 2 のどちらか)
236         * ・<b>NULLABLE</b> int ⇒ NULL は許されるか
237         * ・<b>columnNoNulls</b> - NULL 値を許さない可能性がある
238         * ・<b>columnNullable</b> - 必ず NULL 値を許す
239         * ・<b>columnNullableUnknown</b> - NULL 値を許すかどうかは不明
240         * ・<b>REMARKS</b> String ⇒ コメント記述列 (null の可能性がある)
241         * ・<b>COLUMN_DEF</b> String ⇒ デフォルト値 (null の可能性がある)
242         * ・<b>SQL_DATA_TYPE</b> int ⇒ 未使用
243         * ・<b>SQL_DATETIME_SUB</b> int ⇒ 未使用
244         * ・<b>CHAR_OCTET_LENGTH</b> int ⇒ char の型については列の最大バイト数
245         * ・<b>ORDINAL_POSITION</b> int ⇒ テーブル中の列のインデックス (1 から始まる)
246         * ・<b>IS_NULLABLE</b> String ⇒ "NO" は、列は決して NULL 値を許さないことを意味する。"YES" は NULL 値を許す可能性があることを意味する。空の文字列は不明であることを意味する
247         * ・<b>SCOPE_CATLOG</b> String ⇒ 参照属性のスコープであるテーブルのカタログ (DATA_TYPE が REF でない場合は null)
248         * ・<b>SCOPE_SCHEMA</b> String ⇒ 参照属性のスコープであるテーブルのスキーマ (DATA_TYPE が REF でない場合は null)
249         * ・<b>SCOPE_TABLE</b> String ⇒ 参照属性のスコープであるテーブル名 (DATA_TYPE が REF でない場合は null)
250         * ・<b>SOURCE_DATA_TYPE</b> short ⇒ 個別の型またはユーザ生成 Ref 型、java.sql.Types の SQL 型のソースの型 (DATA_TYPE が DISTINCT またはユーザ生成 REF でない場合は null)
251         *
252         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定
253         *
254         * @param       catalog カタログ名。(カタログ名と一致、"" はカタログなし、null は、カタログ名無条件)
255         * @param       schema  スキーマ名パターン。(スキーマ名と一致、"" はスキーマなし、null は、スキーマ名無条件)
256         * @param       tableName       テーブル名パターン。
257         * @param       columnName      列名パターン
258         *
259         * @return      テーブル列の記述をDBTableModelオブジェクトにラップ
260         * @see java.sql.DatabaseMetaData#getSchemas()
261         */
262        public DBTableModel getColumns( final String catalog,
263                                                                        final String schema,
264                                                                        final String tableName,
265                                                                        final String columnName ) {
266                final DBTableModel table ;
267                Connection       conn   = null ;
268                try {
269                        conn = ConnectionFactory.connection( dbid,appInfo );
270                        final DatabaseMetaData metaData = conn.getMetaData();
271                        // ====== table 求めの個所のみ、異なります。
272                        table = makeDBTableModel( metaData.getColumns(catalog, schema, tableName, columnName) );
273                        // ====== ここまで
274                }
275                catch( final SQLException ex) {
276                        ConnectionFactory.remove( conn,dbid );
277                        conn = null;
278                        throw new HybsSystemException( ex );
279                }
280                finally {
281                        ConnectionFactory.close( conn,dbid );
282                }
283                return table ;
284        }
285
286        /**
287         * 指定されたテーブルのインデックスと統計情報に関する記述を取得します。
288         * それらは、NON_UNIQUE、TYPE、INDEX_NAME、ORDINAL_POSITION によって順序付けされます。
289         * 各インデックス列の記述には次の列があります
290         *
291         * ・<b>TABLE_CAT</b> String ⇒ テーブルカタログ (null の可能性がある)
292         * ・<b>TABLE_SCHEM</b> String ⇒ テーブルスキーマ (null の可能性がある)
293         * ・<b>TABLE_NAME</b> String ⇒ テーブル名
294         * ・<b>NON_UNIQUE</b> boolean ⇒ インデックス値は一意でない値にできるか。TYPE が tableIndexStatistic の場合は false
295         * ・<b>INDEX_QUALIFIER</b> String ⇒ インデックスカタログ (null の可能性がある)。TYPE が tableIndexStatistic の場合は null
296         * ・<b>INDEX_NAME</b> String ⇒ インデックス名。TYPE が tableIndexStatistic の場合は null
297         * ・<b>TYPE</b> short ⇒ インデックスの型
298         *
299         * ・tableIndexStatistic - テーブルのインデックスの記述に連動して返されるテーブルの統計情報を識別する
300         * ・tableIndexClustered - クラスタ化されたインデックス
301         * ・tableIndexHashed - ハッシュ化されたインデックス
302         * ・tableIndexOther - インデックスのその他のスタイル
303         *
304         * ・<b>ORDINAL_POSITION</b> short ⇒ インデックス中の列シーケンス。TYPE が tableIndexStatistic の場合は 0
305         * ・<b>COLUMN_NAME</b> String ⇒ 列名。TYPE が tableIndexStatistic の場合は null
306         * ・<b>ASC_OR_DESC</b> String ⇒ 列ソートシーケンス、"A" ⇒ 昇順、"D" ⇒ 降順、
307                                ソートシーケンスがサポートされていない場合は、null の可能性がある。TYPE が tableIndexStatistic の場合は null
308         * ・<b>CARDINALITY</b> int ⇒ TYPE が tableIndexStatistic の場合、テーブル中の列数。そうでない場合は、インデックス中の一意の値の数
309         * ・<b>PAGES</b> int ⇒ TYPE が tableIndexStatistic の場合、テーブルで使用されるページ数。そうでない場合は、現在のインデックスで使用されるページ数
310         * ・<b>FILTER_CONDITION</b> String ⇒ もしあれば、フィルタ条件 (null の可能性がある)
311         *
312         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定
313         *
314         * @param       catalog カタログ名。(カタログ名と一致、"" はカタログなし、null は、カタログ名無条件)
315         * @param       schema  スキーマ名パターン。(スキーマ名と一致、"" はスキーマなし、null は、スキーマ名無条件)
316         * @param       tableName       テーブル名。このデータベースに格納されたテーブル名と一致しなければならない
317         * @param       unique  true の場合は、一意の値のインデックスだけを返す。false の場合は、一意であるかどうかにかかわらずインデックスを返す
318         * @param       approximate     true の場合は、結果は概数またはデータ値から外れることもある。false の場合は、正確であることが要求される
319         *
320         * @return      インデックスと統計情報に関する記述をDBTableModelオブジェクトにラップ
321         * @see java.sql.DatabaseMetaData#getSchemas()
322         */
323        public DBTableModel getIndexInfo( final String catalog,
324                                                                                final String schema,
325                                                                                final String tableName,
326                                                                                final boolean unique,
327                                                                                final boolean approximate ) {
328                final DBTableModel table ;
329                Connection conn = null ;
330                try {
331                        conn = ConnectionFactory.connection( dbid,appInfo );
332                        final DatabaseMetaData metaData = conn.getMetaData();
333                        // ====== table 求めの個所のみ、異なります。
334                        table = makeDBTableModel( metaData.getIndexInfo(catalog, schema, tableName, unique, approximate) );
335                        // ====== ここまで
336                }
337                catch( final SQLException ex) {
338                        ConnectionFactory.remove( conn,dbid );
339                        conn = null;
340                        throw new HybsSystemException( ex );
341                }
342                finally {
343                        ConnectionFactory.close( conn,dbid );
344                }
345                return table ;
346        }
347
348        /**
349         * 指定されたカタログで使用可能なストアドプロシージャに関する記述を取得します。
350         * スキーマとプロシージャ名の条件に一致するプロシージャの記述だけが返されます。
351         * それらは、PROCEDURE_SCHEM と PROCEDURE_NAME によって順序付けられます。
352         *
353         * 各プロシージャの記述には次の列があります。
354         *
355         * ・PROCEDURE_CAT String ⇒ プロシージャカタログ (null の可能性がある)
356         * ・PROCEDURE_SCHEM String ⇒ プロシージャスキーマ (null の可能性がある)
357         * ・PROCEDURE_NAME String ⇒ プロシージャ名
358         * ・将来使用するための予約
359         * ・将来使用するための予約
360         * ・将来使用するための予約
361         * ・REMARKS String ⇒ プロシージャの説明文
362         * ・PROCEDURE_TYPE short ⇒ プロシージャの種類
363         *
364         * ・procedureResultUnknown - 結果を返す可能性がある
365         * ・procedureNoResult - 結果を返さない
366         * ・procedureReturnsResult - 結果を返す
367         *
368         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定
369         *
370         * @param       catalog カタログ名。(カタログ名と一致、"" はカタログなし、null は、カタログ名無条件)
371         * @param       schema  スキーマ名パターン。(スキーマ名と一致、"" はスキーマなし、null は、スキーマ名無条件)
372         * @param       procName        プロシージャ名パターン。データベースに格納されたプロシージャ名と一致しなければならない
373         *
374         * @return      ストアドプロシージャに関する記述をDBTableModelオブジェクトにラップ
375         * @see java.sql.DatabaseMetaData#getSchemas()
376         */
377        public DBTableModel getProcedures( final String catalog,
378                                                                                final String schema,
379                                                                                final String procName ) {
380                final DBTableModel table ;
381                Connection conn = null ;
382                try {
383                        conn = ConnectionFactory.connection( dbid,appInfo );
384                        final DatabaseMetaData metaData = conn.getMetaData();
385                        // ====== table 求めの個所のみ、異なります。
386                        table = makeDBTableModel( metaData.getProcedures(catalog, schema, procName) );
387                        // ====== ここまで
388                }
389                catch( final SQLException ex) {
390                        ConnectionFactory.remove( conn,dbid );
391                        conn = null;
392                        throw new HybsSystemException( ex );
393                }
394                finally {
395                        ConnectionFactory.close( conn,dbid );
396                }
397                return table ;
398        }
399}