アノテーションを使用したカスタム関数の作成

アノテーションを使用して作成されたカスタム関数は、いくつかのアノテーションが付いた Java クラスです。これらのアノテーションは Virtual DataPort に以下のことを示します。

  1. その Java クラスに、カスタム関数のコードが格納されている。

  2. その Java クラスのメソッドに、そのカスタム関数が呼び出されたときに Virtual DataPort が実行する必要があるコードが格納されている。

各 Java クラスには、カスタム関数を 1 つだけ格納する必要があります。個々のカスタム関数は 1 つ以上のシグネチャを持つことができます。たとえば、同じクラスで関数 function1function1(int)function1(int, text) などの複数のシグネチャで定義できます。

カスタム関数を開発するには、ライブラリ <DENODO_HOME>/lib/contrib/denodo-commons-custom.jar を開発環境のクラスパスに追加します。

その後、以下の手順に従って実施してください。

  1. Java クラスを作成し、そのクラスに @CustomElement (パッケージ com.denodo.common.custom.annotations) のアノテーションを付けます。これには以下のパラメーターがあります。

    • name: 関数の名前。

    • Type: 関数のタイプ。値は次のいずれかです。

      • CustomElementType.VDPFUNCTION: スカラー関数の場合

      • CustomElementType.VDPAGGREGATEFUNCTION: 集計関数の場合

  2. その関数で使用したい各シグネチャに対応するメソッドを追加します。

    たとえば、カスタム関数 function1 をシグネチャ function1(int)function1(int, text) で開発する場合は、以下の 2 つのメソッドを追加します。

    1. @CustomExecutor
      public Integer method1(Integer i) { ... }
      
    2. @CustomExecutor
      public Integer method2(Integer i, String s) { ... }
      

    メソッドパラメーターの型は基本の Java の型 (StringIntegerLongFloat など) でなければなりません。パラメーターでプリミティブ型を使用することはできません。

    関数のシグネチャを表すメソッドには、 @CustomExecutor (パッケージ com.denodo.common.custom.annotations) のアノテーションが付いていなければなりません。

    実行時に、サーバーは、関数に渡されたパラメーターに応じて適切なメソッドを実行します。たとえば、クエリによって関数 function1(int) が呼び出された場合、サーバーは最初のメソッドのコードを実行します。クエリによって関数 function1(int, text) が呼び出された場合は、2 番目のメソッドのコードを実行します。

    クラスは任意の数のメソッドを持つことができますが、シグネチャごとに少なくとも 1 つのメソッドが必要です。また、これらのメソッドは同じクラスでなければなりませんが、カスタム関数から他のクラスのコードを呼び出すことも可能です。

  3. 必要に応じて、 @CustomExecutor アノテーションに syntax パラメーターを追加できます。Administration Tool でカスタム関数の各シグネチャがユーザーに表示されるときに (式エディターのオートコンプリート機能などで)、このパラメーターの値が使用されます。

    この syntax パラメーターの値は、 @CustomParam アノテーション (下記参照) の syntax パラメーターの値より優先されます。そのため、どちらか一方を使用してください。

  4. このカスタム関数をデータベースにプッシュダウンしたい場合は、 delegationPatterns および implementation のパラメーターを @CustomExecutor アノテーションに追加します。このタイプの関数の開発方法の詳細については、「 データベースに委任可能なカスタム関数の開発 」を参照してください。

  5. @CustomExecutor アノテーションが付いたメソッドでは、メソッドの各パラメーターに、 syntax パラメーターを指定した @CustomParam アノテーションを追加できます。

    Syntax パラメーターの値は、この関数のシグネチャが Administration Tool のオートコンプリート機能で表示されるときに、ユーザーフレンドリーなパラメーター名として使用されます。このアノテーションを使用しないと、メソッドの構文は arg1, args2… のように表示されます。

    メソッドの @CustomExecutor アノテーションに syntax パラメーターが指定されている場合は、このパラメーターの値は無視されます。

    @CustomParam アノテーションの mandatory パラメーターの値は無視されます。この値が使用されるのは、このアノテーションがカスタムポリシーの開発に使用されているときだけです。

  6. 集計関数を開発する場合は、集計フィールドを表すパラメーターを @CustomGroup アノテーションでマークします。このようなパラメーターの型は CustomGroupValue でなければなりません。

    groupType パラメーターは、そのグループのエレメントの型です。

    例:

    @CustomExecutor
    public String aggregationFunction(
           @CustomGroup(name="textField", groupType=String.class) CustomGroupValue<String> textField) {
    
          ...
    }
    
  7. @CustomExecutor のアノテーションが付いたメソッドのうち、以下の条件の 1 つ以上に一致する各メソッドに対して、別のメソッドを追加し、そのメソッドに @CustomExecutorReturnType のアノテーションを付ける必要があります。

    • その関数の戻り値の型が array または register である。

    • または、その関数の戻り値の型が入力パラメーターの型に応じて異なる。

    このメソッドの詳細については、「 カスタム関数の戻り値の型 」を参照してください。

データベースに委任可能なカスタム関数の開発

ここでは、Virtual DataPort サーバーによって実行可能なだけでなく、JDBC データソースに委任することも可能なカスタム関数の開発方法について説明します。このような関数の場合、サーバーは、可能であれば、カスタム関数の Java コードを実行する代わりに、データベースの関数を呼び出します。

そのためには、その関数を実装するメソッドの @CustomExecutor アノテーションに以下のパラメーターを追加する必要があります。

  • Implementation: true の場合、その関数のコードが適切な結果を返すこともできることを意味します。関数をデータベースに委任できない場合、サーバーは、このコードを実行します。 false の場合は、カスタム関数のコードが有効ではなく、サーバーはこのコードを実行しないことを意味します。したがって、サーバーはデータベースに関数を委任できなければエラーを返します。

  • delegationPatterns: その関数を委任することができる各データベースの構成を表す DelegationPattern アノテーションの配列。 DelegationPattern には以下の属性があります。

    • databaseName: この関数をサポートしているデータベースの名前。

      この値は、この関数の委任先とする JDBC データソースを作成する CREATE DATASOURCE JDBC ステートメントの DATABASENAME パラメーターの値に対応します。

    • databaseVersions (オプション): この関数をサポートするデータベースのバージョンの配列。このパラメーターが存在しない場合は、この関数が databaseName で示されているデータベースの任意のバージョンに委任可能であることを意味します。この配列の値は、この関数の委任先とする JDBC データソースを作成する CREATE DATASOURCE JDBC ステートメントの DATABASEVERSION パラメーターの値に対応します。

    • Pattern: データベースに委任される式。関数の名前とシグネチャはデータベースごとに異なる場合があるため、このパラメーターは必須です。

      この文字列はある種の正規表現であり、 $0 はカスタム関数に渡す最初のパラメーターを表し、 $1 は 2 番目のパラメーターを表します (以下同様)。

      パラメーターが可変数の引数 (「varargs」) を持つ場合は、 $0[, $i]{1, n} などのパターンを使用できます。

      たとえば、関数のシグネチャが f1(Integer I, String... param) である場合、パターンの値は、 pattern="FUNCTION_IN_DB($0, $1[, $i]{2, n})" のようになります。下の 例 2 では、パラメーターの 1 つが可変数の引数を持つときのパターンの定義方法を示しています。

      pattern パラメーターでは、 [ の文字は、可変数の引数を示す場合にのみ使用できます (例: $0[, $i]{1, n})。この文字をリテラルとして使用することはできません。

注釈

データベースに委任可能なカスタム変数は、名前規則を使用して開発することはできません (「 名前規則を使用したカスタム関数の作成 」を参照)。このようなカスタム関数はアノテーションを使用して開発する必要があります。


例 1: データベースに委任可能なカスタムスカラー関数

3 つの数値の最大数を返す MAX_VALUE というカスタム関数を開発したとします。また、Microsoft SQL Server に、同じ計算を実行する MAXIMUM_N という関数が存在するとします。Oracle にはバージョン 10g と 11g に同じ関数がありますが、 TOP_N という名前になっており、これより前のバージョンにはこの関数は存在しません 1

@CustomExecutor アノテーションにいくつかのパラメーターを追加することによって、Virtual DataPort は、可能であればこの関数を Oracle 10g と 11g、および任意のバージョンの SQL Server に委任するようになります。

カスタム関数をデータベースに委任可能にするためのアノテーションの付け方の例
@CustomElement(type = CustomElementType.VDPFUNCTION, name = "MAX_VALUE")
public class CustomFunctionMaxNumber {
     @CustomExecutor(implementation = true, delegationPatterns = {
             @DelegationPattern(databaseName = "sqlserver",
                                pattern = "MAXIMUM_N($0, $1, $2)"),
             @DelegationPattern(databaseName = "oracle",
                                databaseVersions = { "10g", "11g" },
                                pattern = "TOP_N($0, $1, $2)") })
     public Double Max(
             @CustomParam(name = "arg0") Double arg0,
             @CustomParam(name = "arg1") Double arg1,
             @CustomParam(name = "arg2") Double arg2) {

         /*
         * If the function is not delegated to any of the databases above (e.g. if you use it on a query to
         * base view from Teradata), the execution engine executes this code.
         */
     }
}

最初の @DelegationPattern アノテーションは、SQL Server (任意のバージョン) への関数の委任が可能な場合、サーバーはこの関数を関数 MAXIMUM_3 として委任することを示します。

2 番目の @DelegationPattern は、Oracle のバージョン 10g および 11g への関数の委任が可能な場合 (他のバージョンへの委任は不可能)、サーバーはこの関数を関数 TOP_3 として委任することを示します。


例 2: データベースに委任可能な、可変数の引数を持つカスタムスカラー関数

先ほどと同じ関数を、今度は可変数の引数を使用して開発するとしましょう。この場合、パラメーターを「varargs」として定義する必要があります (パラメーターの型の後にある ... に注目してください)。

カスタム関数をデータベースに委任可能にするためのアノテーションの付け方の例 (2)
@CustomElement(type = CustomElementType.VDPFUNCTION, name = "MAX_VALUE")
public class CustomFunctionMaxNumber {
    @CustomExecutor(implementation = true, delegationPatterns = {
            @DelegationPattern(databaseName = "sqlserver",
                               pattern = "MAXIMUM_N($0[, $i]{1, n})"),
            @DelegationPattern(databaseName = "oracle",
                               databaseVersions = { "10g", "11g" },
                               pattern = "TOP_N($0[, $i]{1, n})") })
    public Double Max(
            @CustomParam(name = "values") Double... arg0) {

         /*
         * If the function is not delegated to any of the databases above (e.g. if you use it on a query to
         * base view from Teradata), the execution engine executes this code.
         */
    }
}

パラメーターの型の後に ... を追加することによって、この関数は 1 つ以上の値を持てるようになります。データベースへの関数の委任方法を定義する pattern パラメーターは、 $0[, $i]{1, n} です。つまり、関数に値 2 を渡した場合、サーバーは Oracle に TOP_N(2) を委任し、パラメーター 2, 3, 4 を渡した場合、サーバーは Oracle に TOP_3(2, 3, 4) を委任します。


例 3: データベースに委任可能なカスタム集計関数

データベースに委任可能なカスタム集計関数
@CustomElement(type = CustomElementType.VDPAGGREGATEFUNCTION, name = "MAX_AGGR_VALUE")
public class CustomAggregationFunction {
    @CustomExecutor(implementation = true, delegationPatterns = {
            @DelegationPattern(databaseName = "sqlserver",
                               pattern = "aggregation_func_sql_server( $0 )"),
            @DelegationPattern(databaseName = "mysql",
                               pattern = "aggregation_func_mysql( $0 )"),
            @DelegationPattern(databaseName = "oracle",
                               databaseVersions = { "10g", "11g" },
                               pattern = "aggregation_func_oracle( $0 )") })
    public String CustomAggregationFunctionSignature1(
            @CustomGroup(name = "field", groupType = String.class)
            CustomGroupValue<String>... textField) {

        /*
         * If the function is not delegated to any of the databases above (e.g. if you use
         * it on a query tobase view from Teradata), the execution engine executes this
         * code.
         */

        return null;
    }
}

脚注

1

これらの関数は SQL Server にも Oracle にも実際には存在しません。例として創作したものです。