Oracle JDBCドライバでLONG列にアクセスする際の注意点
LONG列なんかはもう非推奨で普通はBLOB使うからほとんど問題にはならない内容なのですが。
Oracleのデータディクショナリテーブルの一つALL_TAB_COLUMNS(USER_TAB_COLUMNS)のDATA_DEFAULT列はなんとLONG型で、これにアクセスするときにこの問題にはまって2時間ほど損失したのでメモしておく。
「Oracle JDBCドライバでLONG列を含むテーブルにアクセスする場合は、ResultSetからデータを取得するときLONG列を一番最初に取得しなければならない」
な ん だ そ りゃ
具体的には以下のような現象。
final String SQL_COLUMNINFO = "SELECT " + "col.column_name COLUMN_NAME, " + "col.data_default DATA_DEFAULT, " + //こいつがLONG列 "co.comments COMMENTS " + "FROM " + "user_tab_columns col " + "WHERE " + "col.table_name = 'HOGE' " + "ORDER BY " + "col.table_name, " + "col.column_id "; Statement stmt = null; ResultSet rs = null; try { stmt = conn.createStatement(); rs = stmt.executeQuery(SQL_COLUMNINFO); while(rs.next()) { String columnName = rs.getString("COLUMN_NAME"); String comments = rs.getString("COMMENTS"); String dataDefault = rs.getString("DATA_DEFAULT"); //ここで例外発生 System.out.println(ColumnName + ':' + comments + ':' + dataDefault); } } finally { try { if(rs!=null) rs.close(); } catch (SQLException e) {} try { if(ps!=null) ps.close(); } catch (SQLException e) {} }
上記のような記述だと、getString("DATA_DEFAULT") とした時点で「ORA-17027 ストリームはすでにクローズ済です」が発生する
ここは、以下のようにすると問題が回避できた
final String SQL_COLUMNINFO = "SELECT " + "col.column_name COLUMN_NAME, " + "col.data_default DATA_DEFAULT, " + //こいつがLONG列 "co.comments COMMENTS " + "FROM " + "user_tab_columns col " + "WHERE " + "col.table_name = 'HOGE' " + "ORDER BY " + "col.table_name, " + "col.column_id "; Statement stmt = null; ResultSet rs = null; try { stmt = conn.createStatement(); rs = stmt.executeQuery(SQL_COLUMNINFO); while(rs.next()) { String dataDefault = rs.getString("DATA_DEFAULT"); //最初に読む String columnName = rs.getString("COLUMN_NAME"); String comments = rs.getString("COMMENTS"); System.out.println(ColumnName + ':' + comments + ':' + dataDefault); } } finally { try { if(rs!=null) rs.close(); } catch (SQLException e) {} try { if(ps!=null) ps.close(); } catch (SQLException e) {} }
Oracle Database JDBC開発者ガイドおよびリファレンスにはたしかに「LONG列に後でアクセスしようとしても、データは使用できず、ドライバは「ストリームがクローズされています。」エラーを戻します。」と書いてあるけど。
気づかないよこんなの。
このOracle JDBCドライバのLONG列に対する制限って、Oracle+Javaな界隈では常識レベルの有名な話だったりするのかなあ?ググっても全然出てこなかったよ…
2010/11/13 Javaのコードに一部誤りがあったので修正しました。また、文章の一部を修正しました