アノテーションを使用したカスタム関数の作成¶
アノテーションを使用して作成されたカスタム関数は、いくつかのアノテーションが付いた Java クラスです。これらのアノテーションは Virtual DataPort に以下のことを示します。
その Java クラスに、カスタム関数のコードが格納されている。
その Java クラスのメソッドに、そのカスタム関数が呼び出されたときに Virtual DataPort が実行する必要があるコードが格納されている。
各 Java クラスには、カスタム関数を 1 つだけ格納する必要があります。個々のカスタム関数は 1 つ以上のシグネチャを持つことができます。たとえば、同じクラスで関数 function1
を function1(int)
や function1(int, text)
などの複数のシグネチャで定義できます。
カスタム関数を開発するには、ライブラリ <DENODO_HOME>/lib/contrib/denodo-commons-custom.jar
を開発環境のクラスパスに追加します。
その後、以下の手順に従って実施してください。
Java クラスを作成し、そのクラスに
@CustomElement
(パッケージcom.denodo.common.custom.annotations
) のアノテーションを付けます。これには以下のパラメータがあります。name
: 関数の名前。Type
: 関数のタイプ。値は次のいずれかです。CustomElementType.VDPFUNCTION
: スカラー関数の場合CustomElementType.VDPAGGREGATEFUNCTION
: 集計関数の場合
その関数で使用したい各シグネチャに対応するメソッドを追加します。
たとえば、カスタム関数
function1
をシグネチャfunction1(int)
とfunction1(int, text)
で開発する場合は、以下の 2 つのメソッドを追加します。@CustomExecutor public Integer method1(Integer i) { ... }
@CustomExecutor public Integer method2(Integer i, String s) { ... }
メソッドパラメータの型は基本の Java の型 (
String
、Integer
、Long
、Float
など) でなければなりません。パラメータでプリミティブ型を使用することはできません。関数のシグネチャを表すメソッドには、
@CustomExecutor
(パッケージcom.denodo.common.custom.annotations
) のアノテーションが付いていなければなりません。実行時に、サーバーは、関数に渡されたパラメータに応じて適切なメソッドを実行します。たとえば、クエリによって関数
function1(int)
が呼び出された場合、サーバーは最初のメソッドのコードを実行します。クエリによって関数function1(int, text)
が呼び出された場合は、2 番目のメソッドのコードを実行します。クラスは任意の数のメソッドを持つことができますが、シグネチャごとに少なくとも 1 つのメソッドが必要です。また、これらのメソッドは同じクラスでなければなりませんが、カスタム関数から他のクラスのコードを呼び出すことも可能です。
必要に応じて、
@CustomExecutor
アノテーションにsyntax
パラメータを追加できます。Administration Tool でカスタム関数の各シグネチャがユーザーに表示されるときに (式エディターのオートコンプリート機能などで)、このパラメータの値が使用されます。この
syntax
パラメータの値は、@CustomParam
アノテーション (下記参照) のsyntax
パラメータの値より優先されます。そのため、どちらか一方を使用してください。このカスタム関数をデータベースにプッシュダウンしたい場合は、
delegationPatterns
およびimplementation
のパラメータを@CustomExecutor
アノテーションに追加します。このタイプの関数の開発方法の詳細については、「 データベースに委任可能なカスタム関数の開発 」を参照してください。@CustomExecutor
アノテーションが付いたメソッドでは、メソッドの各パラメータに、syntax
パラメータを指定した@CustomParam
アノテーションを追加できます。Syntax
パラメータの値は、この関数のシグネチャが Administration Tool のオートコンプリート機能で表示されるときに、ユーザーフレンドリーなパラメータ名として使用されます。このアノテーションを使用しないと、メソッドの構文は arg1, args2… のように表示されます。メソッドの
@CustomExecutor
アノテーションにsyntax
パラメータが指定されている場合は、このパラメータの値は無視されます。@CustomParam
アノテーションのmandatory
パラメータの値は無視されます。この値が使用されるのは、このアノテーションがカスタムポリシーの開発に使用されているときだけです。集計関数を開発する場合は、集計フィールドを表すパラメータを
@CustomGroup
アノテーションでマークします。このようなパラメータの型はCustomGroupValue
でなければなりません。groupType
パラメータは、そのグループのエレメントの型です。例:
@CustomExecutor public String aggregationFunction( @CustomGroup(name="textField", groupType=String.class) CustomGroupValue<String> textField) { ... }
@CustomExecutor
のアノテーションが付いたメソッドのうち、以下の条件の 1 つ以上に一致する各メソッドに対して、別のメソッドを追加し、そのメソッドに@CustomExecutorReturnType
のアノテーションを付ける必要があります。その関数の戻り値の型が
array
またはregister
である。または、その関数の戻り値の型が入力パラメータの型に応じて異なる。
このメソッドの詳細については、「 カスタム関数の戻り値の型 」を参照してください。
データベースに委任可能なカスタム関数の開発¶
ここでは、Virtual DataPort サーバーによって実行可能なだけでなく、JDBC データソースに委任することも可能なカスタム関数の開発方法について説明します。このような関数の場合、サーバーは、可能であれば、カスタム関数の Java コードを実行する代わりに、データベースの関数を呼び出します。
そのためには、その関数を実装するメソッドの @CustomExecutor
アノテーションに以下のパラメータを追加する必要があります。
Implementation
:true
の場合、その関数のコードが適切な結果を返すこともできることを意味します。関数をデータベースに委任できない場合、サーバーは、このコードを実行します。false
の場合は、カスタム関数のコードが有効ではなく、サーバーはこのコードを実行しないことを意味します。したがって、サーバーはデータベースに関数を委任できなければエラーを返します。delegationPatterns
: その関数を委任することができる各データベースの構成を表すDelegationPattern
アノテーションの配列。DelegationPattern
には以下の属性があります。databaseName
: この関数をサポートしているデータベースの名前。この値は、この関数の委任先とする JDBC データソースを作成する
CREATE DATASOURCE JDBC
ステートメントのDATABASENAME
パラメータの値に対応します。この属性は、構造が
databaseName/modifier
の修飾子を受け入れます。これにより、カスタム操作を含む特定のデータベースへの委任が可能になります。この機能を使用するには、ドライバーのプロパティで
vdp.database.name.modifier
プロパティを修飾子で指定する必要があります。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」として定義する必要があります (パラメータの型の後にある ...
に注目してください)。
@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;
}
}
定義済みの委任可能な関数の動作をカスタム関数で変更する
このサブセクションでは、定義済みの委任可能な関数の動作をオーバーライドするカスタム関数を作成する方法について説明します。これを行うには、定義済みの関数を組み込む方法のアノテーション @CustomExecutor
を implementation=false
にします。それ以外のパラメータは、必要に応じて変更できます。
例 1: UPPER 関数をオーバーライドするカスタム関数
ここでは、Oracle データベースに対する UPPER 関数をオーバーライドし、キャメルケース関数として動作するように変更する関数を定義します。
@CustomElement(type = CustomElementType.VDPFUNCTION, name = "UPPER")
public class UPPER_SampleVdpFunction {
@CustomExecutor(syntax = "UPPER(String str): String",implementation = false, delegationPatterns = {
@DelegationPattern(databaseName = "oracle",
pattern = "replace(initcap($0),'' '')") })
public String camelCase(String input) {
return null;
}
}
例 2: MAX 集計関数をオーバーライドするカスタム関数
ここでは、Oracle データベースに対する MAX 集計関数をオーバーライドし、最大の絶対値として機能するように変更する関数を定義します。
@CustomElement(type = CustomElementType.VDPAGGREGATEFUNCTION, name = "MAX")
public class MAX_SampleVdpAggregateFunction {
@CustomExecutor(implementation = false, delegationPatterns = {
@DelegationPattern(databaseName = "oracle",
pattern = "MAX (ABS($0))") })
public Integer CustomAggregationFunctionSignature1(
@CustomGroup(name = "field", groupType = Integer.class)
CustomGroupValue<Integer> intField) {
return null;
}
}
脚注
- 1
これらの関数は SQL Server にも Oracle にも実際には存在しません。例として創作したものです。