Criação de UDFs Java¶
Este tópico mostra como criar e instalar uma função definida pelo usuário (UDF) em Java.
Quando você escreve uma UDF em Java, você está escrevendo um código Java para o Snowflake executar como lógica UDF. Esse código Java é o manipulador da UDF. Você implanta a UDF com CREATE FUNCTION, dando um nome à UDF e especificando o método Java como o manipulador a usar quando a UDF é chamada.
Para obter mais exemplos de código, consulte Exemplos de manipuladores de UDF em Java.
Neste tópico:
Como escrever o manipulador de UDF em Java¶
Use os seguintes requisitos e diretrizes ao escrever seu manipulador de UDF em Java.
Defina a classe como pública.
Dentro da classe, declare pelo menos um método público a ser usado como manipulador de UDF.
Para uma UDF inline, declare apenas um método do manipulador. Se, em vez disso, você pretende inserir a classe em um pacote JAR como uma UDF pré-compilada, você pode declarar vários métodos do manipulador, especificando mais tarde cada um como manipulador com a cláusula HANDLER de uma instrução CREATE FUNCTION.
Você pode declarar outros métodos, se necessário, a serem chamados pelo método do manipulador.
Use os seguintes requisitos e diretrizes para cada método do manipulador:
Declare o método do manipulador como público, estático ou não estático.
Se o método não for estático, sua classe também deverá declarar um construtor sem argumentos ou nenhum construtor.
O Snowflake não passa nenhum argumento para o construtor quando ele instancia a classe. Se o construtor lança um erro, o erro é lançado como um erro do usuário, juntamente com a mensagem de exceção.
Especifique um tipo de retorno adequado.
O tipo de retorno deve ser um dos tipos de dados especificados na coluna
Java Data Type
da tabela de mapeamento de tipos SQL-Java. O tipo de retorno deve ser compatível com o tipo de dados SQL especificado na cláusula RETURNS da instrução CREATE FUNCTION.Certifique-se de que cada argumento do método do manipulador (se houver) seja um tipo de dados especificado na coluna
Java Data Type
da tabela de mapeamento de tipos SQL-Java.Ao escolher os tipos de dados das variáveis de Java, leve em conta os valores máximos e mínimos possíveis dos dados que poderiam ser enviados do Snowflake (e devolvidos a ele).
Siga as restrições impostas pelo Snowflake para UDFs de Java em cada método do manipulador e nos métodos chamados por ele.
Criação da função no Snowflake¶
As informações desta seção se aplicam a todas as UDFs de Java, independentemente de o código estar especificado inline ou pré-compilado.
Você deve executar uma instrução CREATE FUNCTION para especificar aspectos da UDF, inclusive:
O nome da UDF.
O nome do método Java que será chamado como manipulador pelo Snowflake quando a UDF for chamada.
O nome da UDF não precisa corresponder ao nome do método do manipulador escrito em Java. A instrução CREATE FUNCTION associa o nome da UDF ao método Java, como mostrado no diagrama a seguir:

Ao escolher um nome para a UDF:
Siga as regras para Identificadores de objetos.
Escolha um nome único ou siga as regras para Sobrecarga de nomes de UDF.
Importante
Ao contrário da sobrecarga para UDFs do SQL, que distingue entre funções baseadas tanto no número quanto nos tipos de dados dos argumentos, as UDFs de Java distinguem entre métodos baseados apenas no número de argumentos. Se dois métodos de Java tiverem o mesmo nome e o mesmo número de argumentos, mas tipos de dados diferentes, então chamar uma UDF usando um desses métodos como manipulador gerará um erro semelhante ao seguinte:
Não é possível determinar qual implementação do “nome do manipulador” será invocada, pois existem múltiplas definições com <number of args> argumentos na função <user defined function name> com manipulador <class name>.<handler name>
Se um warehouse estiver disponível, o erro será detectado no momento em que a UDF for criada. Caso contrário, o erro ocorre quando a UDF é chamada.
A resolução baseada em tipos de dados não é prática, porque alguns tipos de dados de SQL podem ser mapeados para mais de um tipo de dados de Java e, portanto, potencialmente para mais de uma assinatura de UDF de Java.
Os argumentos do método do manipulador são vinculados a argumentos da UDF por posição, não por nome. Em outras palavras, o primeiro argumento da UDF é passado para o primeiro argumento do método, o segundo argumento da UDF é passado para o segundo argumento do método, e assim por diante.
Nos exemplos abaixo, o argumento da UDF do SQL x
corresponde ao argumento do método Java a
, e y
corresponde a b
:
create function add_int_float(x numeric(9, 0), y float)
returns float
language java
handler = 'MyClass.addIntFloat';
public static float addIntFloat(int a, float b) {
// ...
}
Para obter mais informações sobre os tipos de dados de argumentos, consulte Mapeamentos de tipos de dados SQL-Java para tipos de parâmetros e retorno.
Nota
Funções escalares (UDFs) têm um limite de 500 argumentos de entrada.
Recomenda-se que você use o parâmetro RUNTIME_VERSION da instrução CREATE FUNCTION para especificar qual versão do Java runtime suportada deve ser usada, porque a versão padrão pode mudar no futuro.
UDFs inline vs. UDFs pré-compiladas¶
Você pode definir um manipulador de UDF de Java de uma das seguintes maneiras:
Pré-compilada, na qual você insere o manipulador de Java compilado em um JAR e a coloca em um local onde o Snowflake pode lê-la.
A instrução CREATE FUNCTION especifica a localização do arquivo JAR que contém o manipulador. Antes de executar CREATE FUNCTION, você copia o arquivo JAR para um estágio do qual o Snowflake pode lê-lo.
Inline, incluindo o código em Java com a própria declaração da UDF.
A própria instrução CREATE FUNCTION especifica o código-fonte em Java. O Snowflake compila o código-fonte e armazena o código compilado em um arquivo JAR. Você pode especificar um local para o arquivo JAR resultante com a cláusula TARGET_PATH ao executar CREATE FUNCTION.
Se CREATE FUNCTION especificar um local para o arquivo JAR, o Snowflake compilará o código uma vez e manterá o arquivo JAR para uso futuro.
Se CREATE FUNCTION não especificar um local para o arquivo JAR, o Snowflake recompilará o código para cada instrução SQL que chama a UDF, e o Snowflake limpará automaticamente o arquivo JAR após o término da instrução SQL.
Diferenças práticas¶
Vantagens da UDF de Java inline¶
Geralmente são mais fáceis de implementar. Após utilizar suas ferramentas de desenvolvimento para verificar se seu código funciona como deveria, você pode implementá-lo copiando-o para a instrução CREATE FUNCTION e depois executando a instrução. Você pode manter o código lá atualizando e executando CREATE FUNCTION, sem ter que empacotar separadamente a saída compilada de novo em um JAR e atualizá-la em um estágio.
Vantagens da UDF de Java pré-compilada¶
Você pode usá-las quando tiver um arquivo JAR mas sem código-fonte.
Você pode usá-las se o código-fonte for muito grande para colar em uma instrução CREATE FUNCTION. (UDFs de Java inline têm um limite superior para o tamanho do código-fonte).
Uma UDF de Java pré-compilada pode conter várias funções de manipulador. Várias instruções CREATE FUNCTION podem fazer referência ao mesmo arquivo JAR, mas especificar diferentes funções do manipulador dentro do arquivo JAR.
UDFs de Java inline normalmente contêm apenas uma função que pode ser chamada. (Essa função que pode ser chamada pode chamar outras funções, e essas outras funções podem ser definidas na mesma classe ou em outras classes definidas nos arquivos JAR da biblioteca).
Se você tiver ferramentas ou um ambiente para testar ou depurar arquivos JAR, poderá ser mais conveniente fazer a maior parte do trabalho de desenvolvimento em sua UDF usando arquivos JAR. Isso vale particularmente se o código é grande ou complexo.
Adição de dependências ao Classpath¶
Se o código de seu manipulador exigir classes empacotadas em arquivos JAR externos, você poderá adicionar essas dependências ao classpath gerenciado pelo Snowflake disponível para seu manipulador. A seção a seguir descreve como adicionar arquivos JAR ao classpath visível a um manipulador de UDF de Java.
Crie um estágio que esteja disponível para seu manipulador.
Para dependências de UDF, você pode usar um estágio externo ou interno. Se você usar um estágio interno, ele deve ser um usuário ou um estágio nomeado; atualmente, o Snowflake não oferece suporte ao uso de um estágio de tabela para dependências de UDF. Para saber mais sobre a criação de um estágio, consulte CREATE STAGE. Para saber mais sobre a escolha de um tipo de estágio interno, consulte Escolha de um estágio interno para os arquivos locais.
Copie o JAR de dependências para o estágio.
Você pode copiar o JAR de um drive local para um estágio usando o comando PUT. Para obter uma referência do comando, consulte PUT. Para obter mais informações sobre a preparação de arquivos com PUT, consulte Preparação de arquivos de dados de um sistema de arquivo local.
Referencie a dependência JAR ao criar a UDF.
Quando você executar CREATE FUNCTION para criar a UDF, especifique o local do estágio e o caminho e nome do arquivo de todos arquivos de dependências JAR como valores da cláusula IMPORTS. No runtime, o Snowflake adiciona o JAR ao classpath. Para informações de referência, veja CREATE FUNCTION.
O código no exemplo a seguir cria uma UDF chamada
my_udf
, especificando uma dependênciamy_handler_dependency.jar
no estágio@mystage
.CREATE FUNCTION my_udf(i NUMERIC) RETURNS NUMERIC LANGUAGE JAVA IMPORTS = ('@mystage/dependencies/my_handler_dependency.jar') HANDLER = 'MyClass.myFunction' AS $$ // Handler code omitted. $$
Criação de uma UDF de Java inline¶
Para uma UDF inline, você fornece o código-fonte de Java como parte da instrução CREATE FUNCTION.
Você coloca o código-fonte de Java na cláusula AS, delimitando o código com aspas simples ou um par de cifrões ($$
). O uso dos cifrões duplos pode ser mais fácil, por exemplo, quando o código-fonte contém aspas simples.
O código no exemplo a seguir declara uma add
UDF cujo manipulador é o método add
na classe TestAddFunc
.
create function add(x integer, y integer)
returns integer
language java
handler='TestAddFunc.add'
target_path='@~/TestAddFunc.jar'
as
$$
class TestAddFunc {
public static int add(int x, int y) {
return x + y;
}
}
$$;
Dado que o código-fonte de Java pode conter mais de uma classe e mais de um método em uma classe, a cláusula HANDLER especifica a classe e o método a ser usado como manipulador.
Uma UDF de Java inline (como uma UDF de Java pré-compilada) pode chamar código em arquivos JAR que estão incluídos na cláusula CREATE FUNCTION da instrução IMPORTS.
Para obter mais detalhes sobre a sintaxe da instrução CREATE FUNCTION, consulte CREATE FUNCTION.
Para obter mais exemplos, consulte Exemplos de manipuladores de UDF em Java.
Criação de uma UDF de Java pré-compilada¶
Se você pretender criar uma UDF que especifique a localização de um JAR existente para seu manipulador, você desenvolverá o manipulador:
Organizando seus arquivos de código em uma hierarquia para empacotá-los em um arquivo JAR.
Copiando o JAR com sua função de manipulador para um estágio onde o Snowflake poderá lê-lo no runtime.
Organização de seus arquivos¶
Se você planeja compilar o código de Java para criar o arquivo JAR por conta própria, você pode organizar os arquivos da forma mostrada abaixo. Este exemplo assume que você planeja usar o mecanismo de pacote do Java.
developmentDirectory
packageDirectory
class_file1.java
class_file2.java
classDirectory
class_file1.class
class_file2.class
manifest_file.manifest (opcional)
jar_file.jar
put_command.sql
developmentDirectory
Esse diretório contém os arquivos específicos do projeto necessários para criar sua UDF em Java.
packageDirectory
Esse diretório contém os arquivos .java para compilar e incluir no pacote.
class_file#.java
Esses arquivos contêm o código-fonte de Java da UDF.
class_file#.class
Esses são os arquivos .class criados ao compilar os arquivos .java.
manifest_file.manifest
O arquivo do manifesto opcional usado ao combinar os arquivos .class (e, opcionalmente, os arquivos JAR de dependência) com o arquivo JAR.
jar_file.jar
O arquivo JAR que contém o código da UDF.
put_command.sql
Esse arquivo contém o comando SQL PUT para copiar o arquivo JAR em um estágio do Snowflake.
Compilação do código de Java e criação do arquivo JAR¶
Para criar um arquivo JAR contendo o código de Java compilado:
Use o javac para compilar seu arquivo .java em um arquivo .class.
Se você usar um compilador mais novo que a versão 11.x, você poderá usar a opção “–release” para especificar que a versão de destino é a versão 11.
Coloque seu arquivo .class em um arquivo JAR. Você pode empacotar vários arquivos de classe (e outros arquivos JAR) em seu arquivo JAR.
Por exemplo:
jar cf ./my_udf.jar MyClass.class
Um arquivo do manifesto será necessário se sua classe de manipulador estiver em um pacote, e opcional caso contrário. O exemplo a seguir utiliza um arquivo do manifesto:
jar cmf my_udf.manifest ./my_udf.jar example/MyClass.class
Para construir o arquivo jar com todas as dependências incluídas, você pode usar o comando
mvn package
do Maven com o plugin maven-assembly. Para obter mais informações sobre o plugin maven-assembly, veja a página de utilização do Maven.O Snowflake fornece automaticamente as bibliotecas Java padrão (por exemplo,
java.util
). Se seu código chamar essas bibliotecas, você não precisará incluí-las em seu arquivo JAR.Os métodos que você chama nas bibliotecas devem seguir as mesmas restrições impostas pelo Snowflake que seu método Java.
Cópia do arquivo JAR em seu estágio¶
Para que o Snowflake possa ler o JAR que contém seu método do manipulador, você precisa copiar o JAR em um dos seguintes tipos de estágio:
Um estágio interno de usuário ou nomeado.
Atualmente, o Snowflake não oferece suporte ao uso de uma tabela de estágio para armazenar um arquivo JAR com manipuladores da UDF. Para saber mais sobre estágios internos, consulte Escolha de um estágio interno para os arquivos locais.
Um estágio externo.
O estágio que hospeda o arquivo JAR deve ser legível pelo proprietário da UDF.
Normalmente, você carrega o JAR em um estágio interno nomeado usando o comando PUT. Observe que você não pode executar o comando PUT
pelo Snowflake GUI; você pode usar o SnowSQL para executar PUT
. Consulte a seção Exemplos de manipuladores de UDF em Java para obter um exemplo de um comando PUT
para copiar um arquivo .jar em um estágio.
Para saber mais sobre a criação de estágios, consulte CREATE STAGE.
Advertências e práticas recomendadas
Se você apagar ou renomear o arquivo JAR, não poderá mais chamar a UDF.
Se você precisar atualizar seu arquivo JAR:
Atualize-o enquanto nenhuma chamada para a UDF pode ser feita.
Se o antigo arquivo .jar ainda estiver no estágio, o comando
PUT
deverá incluir a cláusulaOVERWRITE=TRUE
.
Nota
Um usuário que atue em relação a UDFs deve ter uma função que tenha recebido as permissões necessárias para a ação. Para obter mais informações, consulte Concessão de privilégios para funções definidas pelo usuário.