Java UDF ハンドラーの例

このトピックには、Javaで記述された UDF ハンドラーコードの簡単な例が含まれています。

Javaを使用して UDF ハンドラーを作成する方法の詳細については、 Java UDF ハンドラーの作成 をご参照ください。

このトピックの内容:

単純なインラインJava UDF の作成と呼び出し

次のステートメントは、インラインJava UDF を作成して呼び出します。このコードは、渡された VARCHAR を返します。

この関数は、オプションの CALLED ON NULL INPUT 句を使用して宣言され、入力の値が NULL であっても関数が呼び出されることを示します。(この関数は、この句の有無にかかわらず NULL を返しますが、たとえば空の文字列を返すように、別の方法で NULL を処理するようにコードを変更できます。)

UDF を作成します。

create or replace function echo_varchar(x varchar)
returns varchar
language java
called on null input
handler='TestFunc.echoVarchar'
target_path='@~/testfunc.jar'
as
'class TestFunc {
  public static String echoVarchar(String x) {
    return x;
  }
}';
Copy

UDF を呼び出します。

SELECT echo_varchar('Hello');
+-----------------------+
| ECHO_VARCHAR('HELLO') |
|-----------------------|
| Hello                 |
+-----------------------+
Copy

NULL のインラインJava UDF への引き渡し

これは、上記で定義された echo_varchar() UDF を使用します。SQL NULL 値は暗黙的にJava null に変換され、そのJava null が返され、暗黙的に SQL NULL に変換されます。

UDF を呼び出します。

SELECT echo_varchar(NULL);
+--------------------+
| ECHO_VARCHAR(NULL) |
|--------------------|
| NULL               |
+--------------------+
Copy

インライン UDF からの明示的な NULL の戻り

次のコードは、 NULL 値を明示的に返す方法を示しています。Java値 null は SQL NULL に変換されます。

UDF を作成します。

create or replace function return_a_null()
returns varchar
null
language java
handler='TemporaryTestLibrary.returnNull'
target_path='@~/TemporaryTestLibrary.jar'
as
$$
class TemporaryTestLibrary {
  public static String returnNull() {
    return null;
  }
}
$$;
Copy

UDF を呼び出します。

SELECT return_a_null();
+-----------------+
| RETURN_A_NULL() |
|-----------------|
| NULL            |
+-----------------+
Copy

OBJECT のインラインJava UDF への引き渡し

次の例では、 SQL OBJECT データ型と対応するJavaデータ型(Map<文字列,文字列>)を使用し、 OBJECT から値を抽出します。この例は、Java UDF に複数のパラメーターを渡すことができることも示しています。

タイプ OBJECT の列を含むテーブルを作成してロードします。

CREATE TABLE objectives (o OBJECT);
INSERT INTO objectives SELECT PARSE_JSON('{"outer_key" : {"inner_key" : "inner_value"} }');
Copy

UDF を作成します。

create or replace function extract_from_object(x OBJECT, key VARCHAR)
returns variant
language java
handler='VariantLibrary.extract'
target_path='@~/VariantLibrary.jar'
as
$$
import java.util.Map;
class VariantLibrary {
  public static String extract(Map<String, String> m, String key) {
    return m.get(key);
  }
}
$$;
Copy

UDF を呼び出します。

SELECT extract_from_object(o, 'outer_key'), 
       extract_from_object(o, 'outer_key')['inner_key'] FROM objectives;
+-------------------------------------+--------------------------------------------------+
| EXTRACT_FROM_OBJECT(O, 'OUTER_KEY') | EXTRACT_FROM_OBJECT(O, 'OUTER_KEY')['INNER_KEY'] |
|-------------------------------------+--------------------------------------------------|
| {                                   | "inner_value"                                    |
|   "inner_key": "inner_value"        |                                                  |
| }                                   |                                                  |
+-------------------------------------+--------------------------------------------------+
Copy

ARRAY のインラインJava UDF への引き渡し

次の例では、 SQL ARRAY データ型を使用しています。

UDF を作成します。

create or replace function multiple_functions_in_jar(array1 array)
returns varchar
language java
handler='TemporaryTestLibrary.handleStrings'
target_path='@~/TemporaryTestLibrary.jar'
as
$$
class TemporaryTestLibrary {
  public static String handleStrings(String[] strings) {
    return concatenate(strings);
  }
  public static String concatenate(String[] strings) {
    int numberOfStrings = strings.length;
    String concatenated = "";
    for (int i = 0; i < numberOfStrings; i++)  {
        concatenated = concatenated + " " + strings[i];
    }
    return concatenated;
  }
}
$$;
Copy

UDF を呼び出します。

SELECT multiple_functions_in_jar(ARRAY_CONSTRUCT('Hello', 'world'));
+--------------------------------------------------------------+
| MULTIPLE_FUNCTIONS_IN_JAR(ARRAY_CONSTRUCT('HELLO', 'WORLD')) |
|--------------------------------------------------------------|
|  Hello world                                                 |
+--------------------------------------------------------------+
Copy

GEOGRAPHY 値のインラインJava UDF への引き渡し

次の例では、 SQL GEOGRAPHY データ型を使用しています。

UDF を作成します。

create or replace function geography_equals(x geography, y geography)
returns boolean
language java
packages=('com.snowflake:snowpark:1.2.0')
handler='TestGeography.compute'
as
$$
import com.snowflake.snowpark_java.types.Geography;

class TestGeography {
  public static boolean compute(Geography geo1, Geography geo2) {
    return geo1.equals(geo2);
  }
}
$$;
Copy

PACKAGES 句を使用して、 Snowparkパッケージ などのSnowflakeシステムパッケージを指定できます。その場合は、 IMPORTS 句の値としてSnowpark JAR ファイルを含める必要はありません。 PACKAGES の詳細については、 CREATE FUNCTION オプションのパラメーター をご参照ください。

データを作成し、そのデータを使用して UDF を呼び出します。

create table geocache_table (id INTEGER, g1 GEOGRAPHY, g2 GEOGRAPHY);

insert into geocache_table (id, g1, g2) select
    1, TO_GEOGRAPHY('POINT(-122.35 37.55)'), TO_GEOGRAPHY('POINT(-122.35 37.55)');
insert into geocache_table (id, g1, g2) select
    2, TO_GEOGRAPHY('POINT(-122.35 37.55)'), TO_GEOGRAPHY('POINT(90.0 45.0)');

select id, g1, g2, geography_equals(g1, g2) as "EQUAL?"
    from geocache_table
    order by id;
Copy

出力は、次と類似したものになります。

+----+--------------------------------------------------------+---------------------------------------------------------+--------+
| ID | G1                                                     | G2                                                      | EQUAL? |
+----+--------------------------------------------------------|---------------------------------------------------------+--------+
| 1  | { "coordinates": [ -122.35, 37.55 ], "type": "Point" } | { "coordinates": [ -122.35,  37.55 ], "type": "Point" } | TRUE   |
| 2  | { "coordinates": [ -122.35, 37.55 ], "type": "Point" } | { "coordinates": [   90.0,   45.0  ], "type": "Point" } | FALSE  |
+----+--------------------------------------------------------+---------------------------------------------------------+--------+
Copy

VARIANT 値のインラインJava UDF への引き渡し

SQL VARIANT 型の値をJava UDF に渡すと、Snowflakeはその値を Snowparkパッケージ で提供される バリアント 型に変換できます。 Variant は、Snowparkパッケージバージョン1.4.0以降でサポートされていることに注意してください。

Snowpark Variant 型は、 Variant 型と他のタイプの間で値を変換するためのメソッドを提供します。

Snowpark Variant 型を使用するには、 PACKAGES 句を使用して、 UDF を作成するときにSnowparkパッケージを指定します。その場合は、 IMPORTS 句の値としてSnowpark JAR ファイルを含める必要はありません。PACKAGES の詳細については、 CREATE FUNCTION オプションのパラメーター をご参照ください。

次の例のコードは、 VARIANT 型として保存された JSON データを受け取り、Snowparkライブラリの Variant 型を使用して、 JSON から price 値を取得します。受信した JSON は、 例で使用されるサンプルデータ に表示されている JSON と同様の構造になっています。

create or replace function retrieve_price(v variant)
returns integer
language java
packages=('com.snowflake:snowpark:1.4.0')
handler='VariantTest.retrievePrice'
as
$$
import java.util.Map;
import com.snowflake.snowpark_java.types.Variant;

public class VariantTest {
  public static Integer retrievePrice(Variant v) throws Exception {
    Map<String, Variant> saleMap = v.asMap();
    int price = saleMap.get("vehicle").asMap().get("price").asInt();
    return price;
  }
}
$$;
Copy

Java UDF ハンドラーを使用したファイルの読み取り

Java UDF ハンドラーコードを使用してファイルの内容を読み取ることができます。ファイルは、ハンドラーが使用できるSnowflakeのステージである必要があります。たとえば、ファイルを読み取って、ハンドラーで非構造化データを処理する場合があります。詳細については、 Java UDFs または UDTFs を使用した非構造化データの処理 をご参照ください。

ステージングされたファイルのコンテンツを読み取るために、Java UDFs または UDTFs は次のことができます。

  • IMPORTS 句 でファイルのパスと名前を指定し、 UDF のホームディレクトリから読み込む。これは、初期化中など、ファイルに静的にアクセスする場合に役立ちます。

  • SnowflakeFile クラスまたは InputStream クラスのメソッドを呼び出す。コンピューティング中、ファイルに動的にアクセスする必要があるときは、これを実行する場合があります。詳細については、このトピック内の SnowflakeFile クラスを使用したファイルの読み取り または InputStream クラスを使用したファイルの読み取り をご参照ください。

    SnowflakeFile は、次のテーブルで説明されているように、 InputStream では利用できない機能を提供します。

    クラス

    入力

    メモ

    SnowflakeFile

    URL フォーマット:

    • 関数の呼び出し元がその所有者でもない場合に、ファイルインジェクション攻撃のリスクを軽減するためのスコープ URL を設定しました。

    • UDF の呼び出し元が所有者でもある場合のファイル URL またはファイルの文字列パス。

    ファイルは、内部または外部ステージに配置する必要があります。

    ファイルサイズなど、追加のファイル属性に簡単にアクセスできます。

    InputStream

    URL フォーマット:

    • 関数の呼び出し元がその所有者でもない場合に、ファイルインジェクション攻撃のリスクを軽減するためのスコープ URL を設定しました。

    • UDF の呼び出し元が所有者でもある場合のファイル URL またはファイルの文字列パス。

    ファイルは、内部または外部ステージに配置する必要があります。

前提条件

ファイルをコードで使用できるようにするには、Javaハンドラーコードがステージ上のファイルを読み取る前に、次を実行する必要があります。

  1. ハンドラーが使用できるステージを作成する。

    外部ステージまたは内部ステージを使用できます。内部ステージを使用する場合は、ユーザーまたは名前付きステージにする必要があります。Snowflakeは現在、 UDF 依存関係のテーブルステージの使用をサポートしていません。ステージの作成の詳細については、 CREATE STAGE をご参照ください。内部ステージ型の選択の詳細については、 ローカルファイルに対する内部ステージの選択 をご参照ください。

    ステージから読み取る SQL アクションを実行するロールには、ステージに対する適切な権限を割り当てる必要があることに注意してください。詳細については、 ユーザー定義関数の権限の付与 をご参照ください。

  2. ステージに、コードで読み取られるファイルをコピーする。

    PUT コマンドを使用して、ファイルをローカルドライブからステージにコピーできます。コマンドリファレンスについては、 PUT をご参照ください。PUT を使用したファイルのステージングについては、 ローカルファイルシステムからのデータファイルのステージング をご参照ください。

IMPORTS を使用したファイルの読み取り

CREATE FUNCTION コマンドの IMPORTS 句にファイル名とステージ名を指定することで、ファイルを読み込めます。

IMPORTS 句でファイルを指定すると、Snowflakeはそのファイルをステージから UDF の ホームディレクトリ (別称 インポートディレクトリ)にコピーします。UDF は、ホームディレクトリから実際にファイルを読み取ります。

インポートされたファイルは単一のディレクトリにコピーされ、そのディレクトリ内で一意の名前を付ける必要があるため、ファイルが異なるステージまたはステージ内の異なるサブディレクトリで開始された場合でも、 IMPORTS 句の各ファイルに異なる名前を付ける必要があります。

次の例では、ファイルを読み取るJava UDF を作成して呼び出します。

以下のJavaソースコードは、 readFile という名前のJavaメソッドを作成します。この UDF はこのメソッドを使用します。

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;

class TestReadRelativeFile {
    public static String readFile(String fileName) throws IOException {
        StringBuilder contentBuilder = new StringBuilder();
        String importDirectory = System.getProperty("com.snowflake.import_directory");
        String fPath = importDirectory + fileName;
        Stream<String> stream = Files.lines(Paths.get(fPath), StandardCharsets.UTF_8);
        stream.forEach(s -> contentBuilder.append(s).append("\n"));
        return contentBuilder.toString();
    }
}
Copy

次の SQL コードは UDF を作成します。このコードは、Javaソースコードがコンパイルされ、 UDF がインポートする TestReadRelativeFile.jar という名前の JAR ファイルに配置されていることを前提としています。2番目と3番目のインポートされたファイル my_config_file_1.txtmy_config_file_2.txt は、 UDF が読み取ることができる構成ファイルです。

CREATE FUNCTION file_reader(file_name VARCHAR)
RETURNS VARCHAR
LANGUAGE JAVA
IMPORTS = ('@my_stage/my_package/TestReadRelativeFile.jar',
           '@my_stage/my_path/my_config_file_1.txt',
           '@my_stage/my_path/my_config_file_2.txt')
HANDLER = 'my_package.TestReadRelativeFile.readFile';
Copy

このコードは UDF を呼び出します。

SELECT file_reader('my_config_file_1.txt') ...;
...
SELECT file_reader('my_config_file_2.txt') ...;
Copy

圧縮形式または非圧縮形式のどちらでファイルにアクセスするかを選択

ステージ内のファイルは、圧縮形式または非圧縮形式で保存できます。ユーザーは、ファイルをステージにコピーする前に圧縮するか、 PUT コマンドにファイルを圧縮するように指示できます。

Snowflakeが GZIP 形式で圧縮されたファイルをステージから UDF ホームディレクトリにコピーする場合、Snowflakeはコピーをそのまま書き込むか、Snowflakeはファイルを書き込む前にコンテンツを解凍できます。

ステージ内のファイルが圧縮されていて、 UDF ホームディレクトリのコピーも圧縮する場合は、 IMPORTS 句でファイル名を指定するときに、元のファイル名(例:「MyData.txt.gz」)を IMPORTS サブ句で使用します。例:

... imports = ('@MyStage/MyData.txt.gz', ...)
Copy

ステージ内のファイルが GZIP 圧縮されているが、 UDF ホームディレクトリのコピーを解凍したい場合は、 IMPORTS 句でファイル名を指定するときに、「.gz」拡張子を省略します。たとえば、ステージに「MyData.txt.gz」が含まれているが、 UDF に非圧縮形式でファイルを読み取らせたい場合は、 IMPORTS 句に「MyData.txt」を指定します。「MyData.txt」という名前の非圧縮ファイルがまだない場合、Snowflakeは「MyData.txt.gz」を検索し、解凍したコピーを UDF ホームディレクトリの「MyData.txt」に自動で書き込みます。UDF は、圧縮されていないファイル「MyData.txt」を開いて読み取ることができます。

スマート解凍は、 UDF ホームディレクトリ内のコピーにのみ適用されます。ステージ内の元のファイルは変更されません。

圧縮ファイルを処理するための次のベストプラクティスに従ってください。

  • 適切なファイル名の規則に従う。ファイルが GZIP 圧縮形式の場合は、ファイル名の末尾に拡張子「.gz」を含める。ファイルが GZIP 圧縮形式でない場合は、ファイル名を「.gz」拡張子で終わらせない。

  • 拡張子「.gz」だけが異なる名前のファイルは作成しない。たとえば、同じステージとディレクトリに「MyData.txt」と「MyData.txt.gz」の両方を作成することや、「MyData.txt」と「MyData.txt.gz」の両方を CREATE FUNCTION コマンドにインポートすることは避けてください。

  • ファイルを2回圧縮しない。たとえば、ファイルを手動で圧縮した後、 AUTO_COMPRESS = FALSE を使用せずにそのファイルを PUT すると、ファイルはもう一度圧縮されます。スマート解凍では1回だけ解凍されるため、データ(または JAR)ファイルが UDF ホームディレクトリに保存されるときには、引き続き圧縮されたままになります。

  • 将来、Snowflakeは、スマート解凍を GZIP 以外の圧縮アルゴリズムに拡張する可能性があります。将来の互換性の問題を防ぐために、これらのベストプラクティスを任意のタイプの圧縮を使用するファイルに適用してください。

注釈

JAR ファイルは、圧縮または非圧縮形式でステージに保存することもできます。Snowflakeは、圧縮されたすべての JAR ファイルを自動的に解凍してから、Java UDF で使用できるようにします。

SnowflakeFile クラスを使用したファイルの読み取り

SnowflakeFile クラスのメソッドを使用すると、Javaハンドラーコードを使用してステージからファイルを読み取ることができます。 SnowflakeFile クラスは、SnowflakeのJava UDF ハンドラーが使用できるクラスパスに含まれています。

注釈

ファイルインジェクション攻撃に対するコードの回復性を高めるには、ファイルの場所を UDF に渡す場合、特に関数の呼び出し元がその所有者でもない場合に、スコープ URL を常に使用します。組み込み関数 build_scoped_file_url を使用して、スコープ URL を SQL に作成できます。 build_scoped_file_url の機能の詳細については、 非構造化データサポートの概要 をご参照ください。

UDF コードをローカルで開発するには、 SnowflakeFile を含んでいるSnowpark JAR をコードのクラスパスに追加します。 snowpark.jar については、 Snowpark Javaの開発環境の設定 をご参照ください。Snowparkクライアントアプリケーションでは、このクラスを使用できないことに注意してください。したがって、クラスはSnowparkトピックに文書化されていません。

SnowflakeFile を使用する場合は、 SQL で CREATE FUNCTION ステートメントを使用する場合のように、 UDF の作成時に、ステージングされたファイル、または SnowflakeFile を含んでいる JAR のいずれかを IMPORTS 句で指定する必要はありません。

SnowflakeFile クラスには次のメソッドがあります。

メソッド

説明

public static native SnowflakeFile newInstance(String url)

url 引数で指定された場所にあるファイルの SnowflakeFile オブジェクトを返します。

public synchronized InputStream getInputStream()

ファイルのコンテンツを読み取るための InputStream オブジェクトを返します。

public synchronized Long getSize()

ファイルのサイズを返します。

次の例のコードは、 SnowflakeFile を使用して、指定されたステージの場所からファイルを読み取ります。 getInputStream メソッドの InputStream を使用して、ファイルの内容を String 変数に読み込みます。

create or replace function sum_total_sales(file string)
returns INTEGER
language java
handler='SalesSum.sumTotalSales'
target_path='@jar_stage/sales_functions2.jar'
as
$$
import java.io.InputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import com.snowflake.snowpark_java.types.SnowflakeFile;

public class SalesSum {

  public static int sumTotalSales(String filePath) throws IOException {
    int total = -1;

    // Use a SnowflakeFile instance to read sales data from a stage.
    SnowflakeFile file = SnowflakeFile.newInstance(filePath);
    InputStream stream = file.getInputStream();
    String contents = new String(stream.readAllBytes(), StandardCharsets.UTF_8);

    // Omitted for brevity: code to retrieve sales data from JSON and assign it to the total variable.

    return total;
  }
}
$$;
Copy

UDF を呼び出してスコープ URL でファイルの場所を渡し、ファイルインジェクション攻撃の可能性を減らします。

select sum_total_sales(build_scoped_file_url('@sales_data_stage', '/car_sales.json'));
Copy

InputStream クラスを使用したファイルの読み取り

ハンドラー関数の引数を InputStream 変数にすると、ファイルの内容を直接 java.io.InputStream に読み込むことができます。これは、関数の呼び出し元が引数としてファイルパスを渡す場合に役立ちます。

注釈

ファイルインジェクション攻撃に対するコードの回復性を高めるには、ファイルの場所を UDF に渡す場合、特に関数の呼び出し元がその所有者でもない場合に、スコープ URL を常に使用します。組み込み関数 build_scoped_file_url を使用して、スコープ URL を SQL に作成できます。 build_scoped_file_url の機能の詳細については、 非構造化データサポートの概要 をご参照ください。

次の例のコードには、 InputStream を受け取り、 int を返すハンドラー関数 sumTotalSales があります。実行時に、Snowflakeは file 変数のパスにあるファイルの内容を stream 引数変数に自動で割り当てます。

create or replace function sum_total_sales(file string)
returns INTEGER
language java
handler='SalesSum.sumTotalSales'
target_path='@jar_stage/sales_functions2.jar'
as
$$
import java.io.InputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class SalesSum {

  public static int sumTotalSales(InputStream stream) throws IOException {
    int total = -1;
    String contents = new String(stream.readAllBytes(), StandardCharsets.UTF_8);

    // Omitted for brevity: code to retrieve sales data from JSON and assign it to the total variable.

    return total;
  }
}
$$;
Copy

UDF を呼び出してスコープ URL でファイルの場所を渡し、ファイルインジェクション攻撃の可能性を減らします。

select sum_total_sales(build_scoped_file_url('@sales_data_stage', '/car_sales.json'));
Copy

ステージングされた簡単なJava UDF の作成と呼び出し

次のステートメントは、単純なJava UDF を作成します。このサンプルは通常、 ファイルの整理 で説明されているファイルとディレクトリの構造に従います。

Javaハンドラーコードを作成しコンパイルする

  1. プロジェクトのルートディレクトリ(ここでは my_udf)に、ソース.javaファイルを保持する src サブディレクトリと、生成された.classファイルを保持する classes サブディレクトリを作成します。

    次のようなディレクトリ階層が必要です。

    my_udf/
    |-- classes/
    |-- src/
    
    Copy
  2. src ディレクトリに、クラスが mypackage パッケージにある.javaファイルを保持する、 mypackage というディレクトリを作成します。

  3. mypackage ディレクトリに、ソースコードを含む MyUDFHandler.java ファイルを作成します。

    package mypackage;
    
    public class MyUDFHandler {
    
      public static int decrementValue(int i)
      {
          return i - 1;
      }
    
      public static void main(String[] argv)
      {
          System.out.println("This main() function won't be called.");
      }
    }
    
    Copy
  4. プロジェクトのルートディレクトリ(ここでは my_udf)から、 javac コマンドを使用してソースコードをコンパイルします。

    次の例の javac コマンドは、 MyUDFHandler.java をコンパイルして、 classes ディレクトリに MyUDFHandler.class ファイルを生成します。

    javac -d classes src/mypackage/MyUDFHandler.java
    
    Copy

    この例には、次の引数が含まれています。

    • -d classes --- 生成されたクラスファイルを書き込むディレクトリ。

    • src/mypackage/MyUDFHandler.java --- .javaファイルへの source_directory/package_directory/Java_file_name 形式のパス。

コンパイルされたコードを JAR ファイルにパッケージ化する

  1. オプションで、プロジェクトのルートディレクトリに、次の属性を含む my_udf.manifest という名前のマニフェストファイルを作成します。

    Manifest-Version: 1.0
    Main-Class: mypackage.MyUDFHandler
    
    Copy
  2. プロジェクトのルートディレクトリから、 jar コマンドを実行して、.classファイルとマニフェストを含む JAR ファイルを作成します。

    次の例の jar コマンドは、 mypackage パッケージフォルダーに生成された MyUDFHandler.class ファイルを my_udf.jar という.jarファイルに配置します。 -C ./classes フラグは、.classファイルの場所を指定します。

    jar cmf my_udf.manifest my_udf.jar -C ./classes mypackage/MyUDFHandler.class
    
    Copy

    この例には、次の引数が含まれています。

    • cmf --- コマンド引数: c は JAR ファイルを作成し、 m は指定された.manifestファイルを使用し、 f は JAR ファイルに指定された名前を付けます。

    • my_udf.manifest --- マニフェストファイル。

    • my_udf.jar --- 作成する JAR ファイルの名前。

    • -C ./classes --- 生成された.classファイルを含むディレクトリ。

    • mypackage/MyUDFHandler.class --- JAR に含める.classファイルのパッケージと名前。

コンパイルされたハンドラーを使用して JAR ファイルをステージにアップロードする

  1. Snowflakeで、 UDF ハンドラーを含む JAR ファイルを保存するために、 jar_stage というステージを作成します。

    ステージの作成の詳細については、 CREATE STAGE をご参照ください。

  2. PUT コマンドを使用して、 JAR ファイルをローカルファイルシステムからステージにコピーします。

put
    file:///Users/Me/my_udf/my_udf.jar
    @jar_stage
    auto_compress = false
    overwrite = true
    ;
Copy

PUT コマンドをスクリプトファイルに保存してから、 SnowSQL を介してそのファイルを実行できます。

snowsql コマンドは次のようになります。

snowsql -a <account_identifier> -w <warehouse> -d <database> -s <schema> -u <user> -f put_command.sql
Copy

この例では、ユーザーのパスワードが SNOWSQL_PWD 環境変数で指定されていることを前提としています。

コンパイルされたコードをハンドラーとして UDF を作成する

UDF を作成します。

create function decrement_value(i numeric(9, 0))
  returns numeric
  language java
  imports = ('@jar_stage/my_udf.jar')
  handler = 'mypackage.MyUDFHandler.decrementValue'
  ;
Copy

UDF を呼び出します。

select decrement_value(-15);
+----------------------+
| DECREMENT_VALUE(-15) |
|----------------------|
|                  -16 |
+----------------------+
Copy

考慮事項

  • クエリが UDF を呼び出してステージングされたファイルにアクセスする場合に、 SQL ステートメントが いずれか の UDF またはUDTF を呼び出すビューもクエリすると、ビューにある関数がステージングされたファイルにアクセスするかどうかにかかわらず、操作に失敗してユーザーエラーが発生します。

  • UDTFs 複数のファイルを並行して処理できます。ただし、 UDFs は現在、ファイルをシリアルに処理しています。回避策として、 GROUP BY 句を使用してサブクエリの行をグループ化します。例については、 Java UDTF の例 をご参照ください。

  • 現在、クエリで参照されているステージングされたファイルが、クエリの実行中に変更または削除された場合、関数の呼び出しはエラーを発生して失敗します。