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 */
016 package org.opengion.fukurou.db;
017
018 import java.io.IOException;
019 import java.io.Reader;
020 import java.sql.Clob;
021 import java.sql.ResultSet;
022 import java.sql.ResultSetMetaData;
023 import java.sql.SQLException;
024 import java.sql.Types;
025 import java.sql.Date;
026 import java.sql.Timestamp;
027 import java.util.Locale;
028
029 import org.opengion.fukurou.util.Closer;
030 import org.opengion.fukurou.util.HybsDateUtil;
031 import static org.opengion.fukurou.util.HybsConst.CR; // 6.1.0.0 (2014/12/26) refactoring
032
033 /**
034 * ResultSet のãƒ??タ処ç�?‚’まとめたクラスですã?
035 * ここでは、ResultSetMetaData から、カラãƒ?•°、カラãƒ?��(NAMEåˆ?ã€?
036 * Type属æ?を取得し、ResultSet で、å?を求める時に、Object型ã?
037 * 処ç�?‚’行いますã?
038 * Object型としては、CLOB、ROWID、TIMESTAMP 型ã?み取り扱ってã�?�¾すã?
039 *
040 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
041 * @og.group ?¤?¢制御
042 *
043 * @version 6.0
044 * @author Kazuhiko Hasegawa
045 * @since JDK6.0,
046 */
047 public class ResultSetValue {
048
049 // /** シスãƒ?ƒ 依存ã?改行記号をセãƒ?ƒˆしますã?4.0.0.0(2007/10/17) */
050 // private static final String CR = System.getProperty( "line.separator" );
051
052 private final ResultSet resultSet ; // å†?ƒ¨で管ç�?�™ã‚?ResultSet オブジェクãƒ?
053 private final int clmSize ; // カラãƒ?‚µイズ
054 private final String[] names ; // カラãƒ?��(ResultSetMetaData#getColumnLabel(int) の toUpperCase)
055 private final int[] type ; // java.sql.Types の定数定義
056 private final boolean useObj ; // オブジェクト型の Type が存在するかどã�?�‹ã€?
057
058 private final int[] size ; // カラãƒ?‚µイズ(ResultSetMetaData#getColumnDisplaySize(int))
059 private final boolean[] isWrit ; // 書き込み許可(ResultSetMetaData#isWritable(int))
060
061 /**
062 * ResultSet を引数にとるコンストラクタ
063 *
064 * ここで、カラãƒ?‚µイズ、カラãƒ?��、java.sql.Types の定数定義 を取得しますã?
065 *
066 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
067 *
068 * @param res å†?ƒ¨で管ç�?�™るResultSetオブジェクãƒ?
069 * @throws java.sql.SQLException ãƒ??タベã?ス・アクセス・エラーが発生したå?å�?
070 */
071 public ResultSetValue( final ResultSet res ) throws SQLException {
072 resultSet = res;
073
074 final ResultSetMetaData metaData = resultSet.getMetaData();
075 clmSize = metaData.getColumnCount();
076 names = new String[clmSize];
077 type = new int[clmSize];
078 size = new int[clmSize];
079 isWrit = new boolean[clmSize];
080
081 boolean tempUseObj = false; // そもそも、オブジェクト系のカラãƒ?�Œあるかどã�?�‹
082 for( int i=0; i<clmSize; i++ ) {
083 final int tp = metaData.getColumnType( i+1 );
084 type[i] = tp ;
085 if( tp == Types.CLOB || tp == Types.ROWID || tp == Types.TIMESTAMP ) { tempUseObj = true; }
086 names[i] = metaData.getColumnLabel(i+1).toUpperCase(Locale.JAPAN) ;
087 size[i] = metaData.getColumnDisplaySize(i+1) ;
088 isWrit[i] = metaData.isWritable(i+1) ;
089 }
090 useObj = tempUseObj ;
091 }
092
093 /**
094 * ResultSetMetaData で求めたã?カラãƒ?•°を返しますã?
095 *
096 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
097 *
098 * @return カラãƒ?•°(ãƒ??タの列数)
099 */
100 public int getColumnCount() { return clmSize ; }
101
102 /**
103 * カラãƒ?��配å?を返しますã?
104 *
105 * 配å?はã€?から始まりã?カラãƒ?•°-1 までのæ–?—型配å?に設定されますã?
106 * カラãƒ?��は、ResultSetMetaData#getColumnLabel(int) ã‚?toUpperCase した
107 * 大æ–?—が返されますã?
108 *
109 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
110 *
111 * @return カラãƒ?��配å?
112 * @og.rtnNotNull
113 */
114 public String[] getNames() {
115 return names.clone();
116 }
117
118 /**
119 * æŒ?®šã?カラãƒ?•ª号のカラãƒ?��を返しますã?
120 *
121 * カラãƒ?��を取得するã?カラãƒ?•ª号はã€?から始まりã?カラãƒ?•°-1 までの数字でæŒ?®šしますã?
122 * ãƒ??タベã?ス上ã?ã€?から始まる番号とは、異なりますã?
123 * カラãƒ?��は、ResultSetMetaData#getColumnLabel(int) ã‚?toUpperCase した
124 * 大æ–?—が返されますã?
125 *
126 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
127 *
128 * @param clmNo カラãƒ?•ª号 (0から始まりã?カラãƒ?•°-1までの数å?
129 * @return æŒ?®šã?カラãƒ?•ª号のカラãƒ?��
130 */
131 public String getColumnName( final int clmNo ) {
132 return names[clmNo];
133 }
134
135 // /**
136 // * java.sql.Types の定数定義配å?を返しますã?
137 // *
138 // * 配å?はã€?から始まりã?カラãƒ?•°-1 までのint型é?列に設定されますã?
139 // * Types の定数定義は、ResultSetMetaData#getColumnType(int) の値ですã?
140 // *
141 // * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
142 // *
143 // * @return カラãƒ?0?žカラãƒ?•°-1)に対応したã?Types定数定義配å?
144 // */
145 // public int[] getSqlTypes() {
146 // return type.clone();
147 // }
148
149 /**
150 * æŒ?®šã?カラãƒ?•ª号のjava.sql.Types の定数定義を返しますã?
151 *
152 * 配å?はã€?から始まりã?カラãƒ?•°-1 までのint型é?列に設定されますã?
153 * Types の定数定義は、ResultSetMetaData#getColumnType(int) の値ですã?
154 *
155 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
156 *
157 * @param clmNo カラãƒ?•ª号 (0から始まりã?カラãƒ?•°-1までの数å?
158 * @return æŒ?®šã?カラãƒ?•ª号のTypes定数
159 */
160 public int getSqlType( final int clmNo ) {
161 return type[clmNo];
162 }
163
164 // /**
165 // * オブジェクト型の Type が存在するかどã�?�‹[true:存在する/false:存在しない]を返しますã?
166 // *
167 // * 基本çš?�«は、å?を求めるå?ç�??å†?ƒ¨ロジãƒ?‚¯でのみ使用しますã?
168 // * Types.CLOB 、Types.ROWID、Types.TIMESTAMP がã?Types定義に含まれてã�?‚‹場合ã?
169 // * true を返しますã?
170 // * 含まれなã�??合ã?、false ですã?
171 // * オブジェクト型 が存在する場合ã?値を求めるå?ç�?�«、専用のメソãƒ?ƒ‰がå¿?¦�になりますã?
172 // * 含まれなã�??合ã?、String.valueOf( Object ) で求めることが可能ですã?
173 // * こã?値を参è€?�«、呼び出すメソãƒ?ƒ‰を変えることで、å?ç�??高é?化を図ろうと
174 // * è€?�ˆてã�?�¾すã?(効果があるかどã�?�‹は、判りませんã€?
175 // *
176 // * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
177 // *
178 // * @return オブジェクト型の Type が存在するかどã�?�‹[true:存在する/false:存在しない]
179 // */
180 // public boolean useObjectType() {
181 // return useObj;
182 // }
183
184 /**
185 * カラãƒ??サイズのint配å?を返しますã?
186 *
187 * 配å?はã€?から始まりã?カラãƒ?•°-1 までのint型é?列に設定されますã?
188 * カラãƒ??サイズは、ResultSetMetaData#getColumnDisplaySize(int) の値ですã?
189 *
190 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
191 *
192 * @return カラãƒ??サイズのint配å?
193 * @og.rtnNotNull
194 */
195 public int[] getColumnDisplaySizes() {
196 return size.clone();
197 }
198
199 /**
200 * æŒ?®šã?カラãƒ?•ª号のサイズを返しますã?
201 *
202 * カラãƒ??サイズは、ResultSetMetaData#getColumnDisplaySize(int) の値ですã?
203 *
204 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
205 *
206 * @param clmNo カラãƒ?•ª号 (0から始まりã?カラãƒ?•°-1までの数å?
207 * @return æŒ?®šã?カラãƒ?•ª号のサイズ
208 */
209 public int getColumnDisplaySize( final int clmNo ) {
210 return size[clmNo];
211 }
212
213 /**
214 * カラãƒ??書き込み可能かどã�?�‹のboolean配å?を返しますã?
215 *
216 * 配å?はã€?から始まりã?カラãƒ?•°-1 までのint型é?列に設定されますã?
217 * カラãƒ??書き込み可能かどã�?�‹は、ResultSetMetaData#isWritable(int) の値ですã?
218 *
219 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
220 *
221 * @return 書き込み可能かどã�?�‹のboolean配å?
222 * @og.rtnNotNull
223 */
224 public boolean[] isWritable() {
225 return isWrit.clone();
226 }
227
228 /**
229 * æŒ?®šã?書き込み可能かどã�?�‹を返しますã?
230 *
231 * カラãƒ??書き込み可能かどã�?�‹は、ResultSetMetaData#isWritable(int) の値ですã?
232 *
233 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
234 *
235 * @param clmNo カラãƒ?•ª号 (0から始まりã?カラãƒ?•°-1までの数å?
236 * @return 書き込み可能かどã�?�‹
237 */
238 public boolean isWritable( final int clmNo ) {
239 return isWrit[clmNo];
240 }
241
242 /**
243 * カーソルを現在の位置からé ?–¹向に1行移動しますã?
244 *
245 * ResultSet#next() を呼び出してã�?�¾すã?
246 * 結果は,すべてæ–?—å?に変換されて格納されますã?
247 *
248 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
249 *
250 * @return 新しい現在の行が有効である場合ã?true、行がそれ以上存在しなã�??合ã?false
251 * @see java.sql.ResultSet#next()
252 * @throws java.sql.SQLException ãƒ??タベã?ス・アクセス・エラーが発生したå?合ã?またã?こã?メソãƒ?ƒ‰がクローズされた結果セãƒ?ƒˆで呼び出されたå?å�?
253 */
254 public boolean next() throws SQLException {
255 return resultSet.next() ;
256 }
257
258 /**
259 * 現在のカーソル位置にあるレコードã?カラãƒ?•ª号のãƒ??タを取得しますã?
260 *
261 * ResultSet#getObject( clmNo+1 ) を呼び出してã�?�¾すã?
262 * 引数のカラãƒ?•ª号はã€?から始まりますが、ResultSet のカラãƒ??はã€?から始まりますã?
263 * æŒ?®šã?ã€?から始まるカラãƒ?•ª号ですã?
264 * 結果は,すべてæ–?—å?に変換されて返されますã?
265 * またã?null オブジェクトã?場合も、ゼロæ–?—å?に変換されて返されますã?
266 *
267 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?: org.opengion.hayabusa.db.DBUtil#getValue( ResultSet , int , int ) から移å‹?
268 *
269 * @param clmNo カラãƒ?•ª号 (0から始まりã?カラãƒ?•°-1までの数å?
270 * @return 現在行ã?カラãƒ?•ª号のãƒ??タ(æ–?—å?)
271 * @throws java.sql.SQLException ãƒ??タベã?ス・アクセス・エラーが発生したå?å�?
272 */
273 public String getValue( final int clmNo ) throws SQLException {
274 final String val ;
275 final Object obj = resultSet.getObject( clmNo+1 );
276 if( obj == null ) {
277 val = "";
278 }
279 else if( useObj ) {
280 switch( type[clmNo] ) {
281 case Types.CLOB : val = getClobData( (Clob)obj ) ;
282 break;
283 case Types.ROWID: val = resultSet.getString(clmNo+1);
284 break;
285 case Types.TIMESTAMP : val = HybsDateUtil.getDate( ((Timestamp)obj).getTime() , "yyyyMMddHHmmss" );
286 break;
287 default : val = String.valueOf( obj );
288 break;
289 }
290 }
291 else {
292 val = String.valueOf( obj );
293 }
294
295 return val ;
296 }
297
298 /**
299 * 現在のカーソル位置にあるレコードã?全カラãƒ?ƒ‡ータを取得しますã?
300 *
301 * #getValue( clmNo ) をã?0から、カラãƒ?•°-1 まで呼び出して求めた文字å?配å?を返しますã?
302 *
303 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?
304 *
305 * @return 現在行ã?全カラãƒ?ƒ‡ータのæ–?—å?配å?
306 * @throws java.sql.SQLException ãƒ??タベã?ス・アクセス・エラーが発生したå?å�?
307 */
308 public String[] getValues() throws SQLException {
309 final String[] vals = new String[clmSize];
310
311 for( int i=0; i<clmSize; i++ ) {
312 vals[i] = getValue( i );
313 }
314
315 return vals ;
316 }
317
318 /**
319 * タイプに応じて変換されたã?Numberオブジェクトを返しますã?
320 *
321 * 条件に当てはまらなã�??合ã?、null を返しますã?
322 * org.opengion.hayabusa.io.HybsJDBCCategoryDataset2 から移動してきましたã€?
323 * これは、検索結果をグラフ化する為の 値を取得する為のメソãƒ?ƒ‰ですã?でã€?
324 * 数値に変換できなã�??合ã?、エラーになりますã?
325 *
326 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?: org.opengion.hayabusa.db.DBUtil#getNumber( int , Object ) から移å‹?
327 *
328 * @param clmNo カラãƒ?•ª号 (0から始まりã?カラãƒ?•°-1までの数å?
329 * @return Numberオブジェクãƒ?条件に当てはまらなã�??合ã?、null)
330 * @see java.sql.Types
331 * @throws java.sql.SQLException ãƒ??タベã?ス・アクセス・エラーが発生したå?å�?
332 * @throws RuntimeException 数字変換できなかったå?合ã?
333 */
334 public Number getNumber( final int clmNo ) throws SQLException {
335 final Object obj = resultSet.getObject( clmNo+1 );
336 Number value = null;
337
338 switch( type[clmNo] ) {
339 case Types.TINYINT:
340 case Types.SMALLINT:
341 case Types.INTEGER:
342 case Types.BIGINT:
343 case Types.FLOAT:
344 case Types.DOUBLE:
345 case Types.DECIMAL:
346 case Types.NUMERIC:
347 case Types.REAL: {
348 value = (Number)obj;
349 break;
350 }
351 case Types.DATE:
352 case Types.TIME: {
353 value = Long.valueOf( ((Date)obj).getTime() );
354 break;
355 }
356 // 5.6.2.1 (2013/03/08) Types.DATE と Types.TIMESTAMP で処ç�?‚’åˆ?�‘ますã?
357 case Types.TIMESTAMP: {
358 value = Long.valueOf( ((Timestamp)obj).getTime() );
359 break;
360 }
361 case Types.CHAR:
362 case Types.VARCHAR:
363 case Types.LONGVARCHAR: {
364 final String str = (String)obj;
365 try {
366 value = Double.valueOf(str);
367 }
368 catch (NumberFormatException ex) {
369 final String errMsg = "数字変換できませんでした。in=" + str
370 + CR + ex.getMessage() ;
371 throw new RuntimeException( errMsg,ex );
372 // suppress (value defaults to null)
373 }
374 break;
375 }
376 default:
377 // not a value, can't use it (defaults to null)
378 break;
379 }
380
381 return value;
382 }
383
384 /**
385 * カラãƒ??タイプを表現するæ–?—å?値を返しますã?
386 *
387 * こã?æ–?—å?を用ã�?�¦、CCSファイルでタイプごとの表示方法を
388 * æŒ?®šすることができますã?
389 * 現時点では、VARCHAR2,LONG,NUMBER,DATE,CLOB,NONE のどれかにあてはめますã?
390 *
391 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?: org.opengion.hayabusa.db.DBUtil#type2ClassName( int ) から移å‹?
392 *
393 * @param clmNo カラãƒ?•ª号 (0から始まりã?カラãƒ?•°-1までの数å?
394 * @return カラãƒ??タイプを表現するæ–?—å?値
395 * @see java.sql.Types
396 */
397 public String getClassName( final int clmNo ) {
398 final String rtn ;
399
400 switch( type[clmNo] ) {
401 case Types.CHAR:
402 case Types.VARCHAR:
403 case Types.BIT:
404 rtn = "VARCHAR2"; break;
405 case Types.LONGVARCHAR:
406 rtn = "LONG"; break;
407 case Types.TINYINT:
408 case Types.SMALLINT:
409 case Types.INTEGER:
410 case Types.NUMERIC:
411 case Types.BIGINT:
412 case Types.FLOAT:
413 case Types.DOUBLE:
414 case Types.REAL:
415 case Types.DECIMAL:
416 rtn = "NUMBER"; break;
417 case Types.DATE:
418 case Types.TIME:
419 case Types.TIMESTAMP:
420 rtn = "DATE"; break;
421 case Types.CLOB:
422 rtn = "CLOB"; break;
423 default:
424 rtn = "NONE"; break;
425 }
426
427 return rtn;
428 }
429
430 /**
431 * Clob オブジェクトから文字å?を取りå?しますã?
432 *
433 * @og.rev 6.0.4.0 (2014/11/28) 新規作æ?: org.opengion.hayabusa.db.DBUtil#getClobData( Clob ) から移å‹?
434 *
435 * @param clobData Clobオブジェクãƒ?
436 * @return Clobオブジェクトから取りå?したæ–?—å?
437 * @throws SQLException ãƒ??タベã?スアクセスエラー
438 * @throws RuntimeException 入出力エラーが発生したå?å�?
439 * @og.rtnNotNull
440 */
441 private String getClobData( final Clob clobData ) throws SQLException {
442 if( clobData == null ) { return ""; }
443
444 final StringBuilder buf = new StringBuilder( 10000 );
445
446 Reader reader = null;
447 try {
448 reader = clobData.getCharacterStream();
449 final char[] ch = new char[10000];
450 int len ;
451 while( (len = reader.read( ch )) >= 0 ) {
452 buf.append( ch,0,len );
453 }
454 }
455 catch( IOException ex ) {
456 final String errMsg = "CLOBãƒ??タの読み込みに失敗しましたã€?
457 + ex.getMessage() ;
458 throw new RuntimeException( errMsg,ex );
459 }
460 finally {
461 Closer.ioClose( reader );
462 }
463 return buf.toString();
464 }
465 }