JDBC インターフェイスの詳細

ここでは、Denodo の JDBC ドライバーに固有の情報について説明します。

ビューとそのフィールドの説明

このドライバーは、ビューとそのフィールドの説明を、テーブルまたはビュー、およびそのフィールドのメタデータの [REMARKS] 列に公開します。

blob 値のコンテンツタイプの取得

このドライバーは、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 で日時パラメーターを設定するためのメソッド

PreparedStatement でその型のパラメーターを設定するためのメソッド

localdate

以下のいずれか

  • PreparedStatement.setObject(java.time.LocalDate)

  • PreparedStatement.setDate(java.sql.Date)

例:

// 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

以下のいずれか

  • PreparedStatement.setObject(java.time.LocalTime)

  • PreparedStatement.setTime(java.sql.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

以下のいずれか

  • PreparedStatement.setObject(java.time.OffsetDateTime)

  • PreparedStatement.setTimestamp(java.sql.Timestamp)

例:

// 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

この値を java.time.Period オブジェクトに変換するには、 java.time.Period.ofMonths (value) を呼び出します。

ドライバーから Duration オブジェクトを取得するには、 ResultSet.getObject(col, java.time.Period.class) を呼び出します。

interval_day_second

java.lang.Long

java.lang.Long

この値を java.time.Duration オブジェクトに変換するには、 java.time.Duration. ofMillis(value) を呼び出します。

ドライバーから Duration オブジェクトを取得するには、 ResultSet.getObject(col, java.time.Duration.class) を呼び出します。

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 ドライバーを使用して以下のことを行う方法について説明します。

  1. Struct オブジェクトのサブフィールドの名前を取得する

  2. サブフィールドの値を register の内部の位置ではなくその名前で取得する

たとえば、アプリケーションで last_name サブフィールドと first_name サブフィールドが含まれる register フィールドを返すクエリを実行するとします。行ごとに、結果セットは Struct オブジェクトを返します。各 Struct オブジェクトの値を取得するには、アプリケーションは Struct.getAttributes() メソッドを呼び出す必要があります。このメソッドは、姓と名の 2 つの値の配列を返します。その後、このレジスターを変更してサブフィールド (たとえば telephone) を追加した場合、 Struct.getAttributes() によって返される配列には、2 つではなく 3 つのエレメントが含まれます。また、配列の最初のエレメントが名ではなく電話番号になっている場合、アプリケーションは無効なデータを取得します。

こうした保全性の問題を回避するには、Denodo JDBC API のクラスを使用して Struct の値をレジスター内の位置ではなく名前で取得します。そうすることで、変更に対するアプリケーションの堅牢性が向上します。

次の例に、これを行う方法を示します。

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 」を参照してください。