JDBC インターフェイスの詳細¶
ここでは、Denodo の JDBC ドライバーに固有の情報について説明します。
ビューとそのフィールドの説明¶
このドライバーは、ビューとそのフィールドの説明を、テーブルまたはビュー、およびそのフィールドのメタデータの [REMARKS] 列に公開します。
blob 値のコンテンツタイプの取得¶
このドライバーは、blob フィールドの コンテンツタイプ を使用できるようにします。次の例に、その方法を示します。
ResultSet rs = stmt.executeQuery(...);
...
com.denodo.vdb.jdbcdriver.VDBJDBCBlob blob =
(com.denodo.vdb.jdbcdriver.VDBJDBCBlob) rs.getBlob(index);
String contentType = blob.getContentType();
Denodo JDBC ドライバーを使用した日時値の操作¶
以下のサブセクションでは、JDBC ドライバーを使用してさまざまな日時値を操作する方法について説明します。
準備済みステートメントのパラメーターでの日時値の設定¶
次の表に、パラメーター (「?」) の値を設定するために呼び出す必要がある PreparedStatement クラスのメソッドを、値の型ごとに示します。
型 |
PreparedStatement でその型のパラメーターを設定するためのメソッド |
---|---|
localdate |
以下のいずれか
例: // Creating a LocalDate object
setObject(1, java.time.LocalDate.of(2018,01,15));
// Creating a Date object
setDate(1, java.sql.Date.valueOf("2018-01-15"));
java.sql.Date クラスのドキュメントによれば、「setDate」を使用する場合、「Date」オブジェクトを「正規化」する必要があります。そのためには、インスタンスが関連付けられている特定のタイムゾーンの時間、分、秒、およびミリ秒を 0 に設定します。そのため、LocalDate オブジェクトの方が簡単に使用できます。 |
time |
以下のいずれか
例: // Creating a LocalTime object
setObject(1, LocalTime.of(11, 58, 59, 123000000));
// Creating a java.sql.Time object
setTime(2, java.sql.Time.valueOf("11:58:59"));
java.sql.Time クラスのドキュメントによれば、「setTime」を使用する場合、Time オブジェクトの日付コンポーネントを、1970 年 1 月 1 日の「ゼロエポック」値に設定する必要があります。そのため、LocalTime オブジェクトの方が簡単に使用できます。 |
timestamp |
PreparedStatement.setObject(java.time.LocalDateTime) 例: setObject(1, java.time.LocalDateTime.of(
2018, 01, 15, 23, 58, 59, 256000000))
最後のパラメーターは、値がナノ秒単位であるため 256 ミリ秒を表します。Denodo では、timestamp、timestamptz、および time の最大精度はナノ秒ではなくミリ秒です。 PreparedStatement.setTimeStamp() を使用する場合は、timestamptz 値を指定する必要があります。そうしないと、クエリに timestamptz から timestamp へのキャストがある場合を除き、クエリは失敗します。また、キャストがある場合でも、それが機能するには、コネクション URI のパラメーター i18n が Denodo サーバーの i18n 設定と一致する必要があります。 |
date (非推奨) |
timestamptz と同じ (以下を参照) |
timestamptz |
以下のいずれか
例: // Creating an OffsetDateTime object
setObject(1, OffsetDateTime.parse(
"2018-01-01T21:15:00+01:00"))
// Creating a Timestamp object
SimpleDateFormat sdf =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss XXX");
sdf.setTimeZone("GMT");
setTimestamp(
1
, sdf.parse("1982-12-13 01:59:59 +0000"));
|
interval_year_month |
setObject(java.time.Period) 例: // Equivalent to INTERVAL '145-11' YEAR TO MONTH
setObject(1, Period.ofYears(145).plusMonths(11));
// Equivalent to INTERVAL '145' YEAR
setObject(Period.ofYears (145));
|
interval_day_second |
setObject(java.time.Duration) 例: // Equivalent to INTERVAL '4 5:12' DAY TO MINUTE
setObject(Duration.ofDays(4).plusHours(5).plusMinutes(12));
// Equivalent to INTERVAL '4 5:12:10.222' DAY TO SECOND
setObject(Duration.parse("P4DT5H12M10.222S"));
|
ドライバーが日時型と時間間隔型をレポートする方法¶
次の表に、JDBC ドライバーが各日時型をレポートする方法を示します。
Denodo の型名 |
ResultSetMetaData.getColumnTypeName() メソッドで返される型名 |
ResultSetMetaData.getColumnType(int) メソッドで返される値 |
---|---|---|
localdate |
DATE |
91 |
time |
TIME |
92 |
timestamp |
TIMESTAMP |
93 |
date (非推奨) |
TIMESTAMP_WITH_TIMEZONE |
2014 |
timestamptz |
TIMESTAMP_WITH_TIMEZONE |
2014 |
interval_year_month |
INTERVAL_YEAR_MONTH |
2020 |
interval_day_second |
INTERVAL_DAY_SECOND |
2021 |
date
型および timestamptz
型は同じ型 (TIMESTAMP WITH TIMEZONE) でレポートされるため、クライアントアプリケーションはこれらを区別できません。これは、Denodo 6.0 以前のバージョンから Denodo 8.0 へのアップグレードを容易にするための意図的な動作です。クライアントアプリケーションはこれらの型を区別する必要はなく、どちらも timestamptz
として扱います。
interval_year_month
型および interval_day_second
型は JDBC API に含まれていないため、それらのコードは Denodo によって定義されています。
Denodo の型名 |
ResultSetMetaData.getColumnClassName(int) の結果 |
ResultSet.getObject() クラスによって返されるオブジェクトの Java クラス |
---|---|---|
localdate |
java.sql.Date |
java.sql.Date |
time |
java.sql.Time |
java.sql.Time |
timestamp |
java.sql.Timestamp |
java.sql.Timestamp |
date (非推奨) |
java.sql.Timestamp |
java.sql.Timestamp |
timestamptz |
java.sql.Timestamp |
java.sql.Timestamp |
interval_year_month |
java.lang.Long |
java.lang.Long この値を ドライバーから |
interval_day_second |
java.lang.Long |
java.lang.Long この値を ドライバーから |
Struct (レジスター) 内部のエレメント名の取得¶
Denodo の JDBC ドライバーは、複合値を JDBC API のクラスに変換します。
register
型の値を java.sql.Struct オブジェクトに変換します。array
型の値を java.sql.Array オブジェクトに変換します。java.sql.Array
オブジェクトはStruct
オブジェクトの配列です。
標準の JDBC API では、 java.sql.Struct
オブジェクトの内部 (register
フィールドの内部など) にある値を取得するメソッドが提供されています。しかし、 Struct
のサブフィールドの名前を取得する方法や、サブフィールドの名前でこれらの値を取得する方法は提供されていません。
ここでは、Denodo JDBC ドライバーを使用して以下のことを行う方法について説明します。
Struct
オブジェクトのサブフィールドの名前を取得するサブフィールドの値を
register
の内部の位置ではなくその名前で取得する
たとえば、アプリケーションで last_name
サブフィールドと first_name
サブフィールドが含まれる register
フィールドを返すクエリを実行するとします。行ごとに、結果セットは Struct
オブジェクトを返します。各 Struct
オブジェクトの値を取得するには、アプリケーションは Struct.getAttributes()
メソッドを呼び出す必要があります。このメソッドは、姓と名の 2 つの値の配列を返します。その後、このレジスターを変更してサブフィールド (たとえば telephone
) を追加した場合、 Struct.getAttributes()
によって返される配列には、2 つではなく 3 つのエレメントが含まれます。また、配列の最初のエレメントが名ではなく電話番号になっている場合、アプリケーションは無効なデータを取得します。
こうした保全性の問題を回避するには、Denodo JDBC API のクラスを使用して Struct
の値をレジスター内の位置ではなく名前で取得します。そうすることで、変更に対するアプリケーションの堅牢性が向上します。
次の例に、これを行う方法を示します。
import com.denodo.vdb.jdbcdriver.printer.Field;
import com.denodo.vdb.jdbcdriver.VDBJDBCResultSetMetaData;
import com.denodo.vdb.vdbinterface.common.clientResult.vo.descriptions.type.RegisterVO;
import com.denodo.vdb.vdbinterface.common.clientResult.vo.descriptions.type.RegisterValueVO;
...
public static void main(String[] args)
throws Exception {
/*
* The method getConnection() returns a Connection to Virtual
* DataPort
*/
Connection connection = getConnection();
Statement st = connection.createStatement();
String query = "SELECT * FROM view_with_compound_fields";
ResultSet rs = st.executeQuery(query);
/*
* The classes 'VDBJDBCResultSetMetaData' and 'Field' are part
* of the Denodo JDBC API. They do not belong to the standard
* JDBC API.
*/
VDBJDBCResultSetMetaData metaData =
(VDBJDBCResultSetMetaData) rs.getMetaData();
Field[] fields = metaData.getFields();
while (rs.next()) {
int columnCount = metaData.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
Object value = rs.getObject(i);
if (value != null) {
if (metaData.getColumnType(i) == Types.STRUCT) {
/*
* The JDBC API represents the values of type
* 'register' as 'Struct' objects.
*/
/*
* The classes 'RegisterVO' and
* 'RegisterValueVO' are part of the Denodo JDBC
* API. They do not belong to the standard Java
* API.
*/
RegisterVO vdpType =
((RegisterVO) fields[i - 1].getVdpType());
List<RegisterValueVO> registerSubTypes =
vdpType.getElements();
Struct struct = (Struct) value;
Object[] structValues = struct.getAttributes();
String firstName = null, lastName = null;
for (int j=0; j < registerSubTypes.size(); j++) {
/*
* The variable 'registerSubTypes'
* contains the names of the names of the
* subfields.
*/
String subFieldName =
registerSubTypes.get(j).getName();
switch (subFieldName) {
case "first_name":
firstName = (String) structValues[j];
break;
case "last_name":
lastName = (String) structValues[j];
break;
}
/*
* ...
*/
}
} else if (metaData.getColumnType(i)==Types.ARRAY) {
/*
* The JDBC API represents the values of type
* 'array' as 'Array' objects.
*/
Object[] register =
(Object[]) rs.getArray(i).getArray();
for (Object o : register) {
/*
* In the Denodo JDBC API, the content of an
* 'Array' is an array of 'Struct' objects.
*/
Struct s = (Struct) o;
/*
* ...
*/
}
} // else ...
}
}
}
/*
* Close ResultSet, Statement and Connection.
*/
}
受信シリアライズデータをフィルターするアプリケーションからの接続¶
Denodo JDBC ドライバーは、Java Remote Method Invocation (RMI) を使用して Virtual DataPort に接続します。一部のクライアントアプリケーション (Oracle WebLogic Server の最新バージョンなど) には、RMI を使用して受信したデータをフィルターするメカニズムが組み込まれています。このメカニズムを使用すると、クライアントアプリケーションのセキュリティが強化されます。しかし、アプリケーションにこのフィルターがデフォルトで構成されていると、Denodo からのデータを受信できなくなる場合があります。
このフィルターが有効になっているアプリケーションから Denodo に接続する場合、アプリケーションの管理者は、このフィルターを制御するパラメーターに次の文字列を追加する必要があります。
com.denodo.**
このフィルターの設定は、クライアントアプリケーションによって異なります。
この詳細については、公式の仕様である「 JEP 290: Filter Incoming Serialization Data 」を参照してください。