Como adicionar lógica de aplicativo a um pacote de aplicativo¶
Este tópico descreve como adicionar lógica de aplicativo ao script de configuração de um pacote de aplicativo. Ele também descreve como usar arquivos de código externos em um pacote de aplicativo.
Consulte Adição de experiência front-end a um aplicativo usando Streamlit para obter mais informações sobre como incluir um aplicativo Streamlit em um pacote de aplicativo.
Considerações sobre o uso de procedimentos armazenados e funções¶
O Snowflake Native App Framework permite incluir procedimentos armazenados, funções definidas pelo usuário (UDFs) e funções externas em um pacote de aplicativo. Estes podem ser escritos em qualquer uma das linguagens com suporte Snowflake.
Adição do código do aplicativo com segurança¶
Todos os procedimentos armazenados e UDFs dentro de um Snowflake Native App são executados como o aplicativo e têm acesso a todos os objetos dentro do Snowflake Native App instalado. Isso pode levar a ataques de injeção SQL.
Ao desenvolver procedimentos e funções para uso em um Snowflake Native App, a Snowflake recomenda que todos os comandos SQL que exigem entrada de usuários sejam executados usando parâmetros vinculados. Isso inclui entrada fornecida por meio de argumentos de procedimento.
Consulte Criação de um procedimento armazenado para obter mais informações.
Sobre os direitos do chamador e os direitos do proprietário¶
Todos os procedimentos criados pelo script de configuração ou executados no Snowflake Native App instalado devem ser executados com os direitos do proprietário (EXECUTE AS OWNER).
Essa restrição existe porque se o Snowflake Native App fosse executado com os direitos do chamador (EXECUTE AS CALLER) em um procedimento que o Snowflake Native App não possui, o procedimento seria executado como o próprio Snowflake Native App e permitiria que um consumidor criasse código para visualizar ou modificar o conteúdo de Snowflake Native App e conteúdo de dados compartilhados.
Consulte Understanding Caller’s Rights and Owner’s Rights Stored Procedures para obter mais informações.
Limitações ao chamar funções de contexto do script de configuração¶
As funções de contexto fornecem informações sobre o contexto no qual uma instrução é executada. Dentro do contexto de Snowflake Native App Framework, algumas funções de contexto não estão disponíveis. As funções de contexto que não estão disponíveis são bloqueadas e retornam um erro ou sempre retornam um valor nulo.
Em geral, você deve ter cuidado ao usar funções de contexto em políticas aplicadas ao conteúdo de dados compartilhados em um Snowflake Native App. Algumas funções, por exemplo CURRENT_IP_ADDRESS, se comportam de maneira diferente no contexto de um Snowflake Native App.
Observe que ao usar funções de contexto que dependem do namespace na organização do cliente, pode haver conflitos com funções em outros namespaces. Por exemplo, uma política de acesso a linhas usando CURRENT_USER deve estar ciente de que o mesmo nome de usuário pode existir em várias contas.
A tabela a seguir lista as funções de contexto que não são compatíveis com o Snowflake Native App Framework:
Função de contexto |
Bloqueado em conteúdo compartilhado (retorna nulo) |
Bloqueado em scripts de configuração e procedimento armazenado e UDFs de propriedade do Snowflake Native App (lança uma exceção). |
---|---|---|
CURRENT_ROLE |
✔ |
|
CURRENT_ROLE_TYPE |
✔ |
|
CURRENT_USER |
✔ |
|
IS_ROLE_IN_SESSION |
✔ |
|
CURRENT_IP_ADDRESS |
✔ |
✔ |
CURRENT_AVAILABLE_ROLES |
✔ |
✔ |
CURRENT_SECONDARY_ROLES |
✔ |
✔ |
ALL_USER_NAMES |
✔ |
|
GET_USERS_FOR_COLLABORATION |
✔ |
|
CURRENT_WAREHOUSE |
✔ |
|
SYSTEM$ALLOWLIST |
✔ |
Como usar funções e procedimentos do Snowpark em um pacote de aplicativo¶
O Snowflake Native App Framework oferece suporte às bibliotecas Snowpark para criação de procedimentos armazenados em Java, Scala e Python.
Referência a arquivos de código externos¶
Existem dois tipos de arquivos de código que você pode incluir em um pacote de aplicativo:
Arquivos referenciados: incluem binários, bibliotecas e outros arquivos de código. Esses arquivos são específicos de uma versão definida em um pacote de aplicativo. Esses arquivos devem estar localizados no diretório raiz do estágio ao criar ou adicionar uma versão a um pacote de aplicativo.
Os arquivos referenciados são diferentes das funções definidas pelo usuário e dos procedimentos armazenados porque não são definidos no script de configuração de um pacote de aplicativo. Esses arquivos são referenciados por instruções de importação dentro dos procedimentos armazenados e UDFs definidos no script de configuração.
Arquivos de recursos: incluem dados semiestruturados, dados estruturados e binários, por exemplo, um modelo de aprendizado de máquina. Esses arquivos devem ser carregados em um estágio nomeado acessível ao pacote de aplicativo.
Um procedimento armazenado, função definida pelo usuário ou função externa que faz referência a esses tipos de arquivos de código deve ser criado em um esquema com versão no script de configuração. Ao criar procedimentos armazenados ou funções em um esquema com versão, você deve fazer referência a um arquivo de código relativo ao diretório raiz do estágio nomeado.
Por exemplo, se o diretório raiz do estágio nomeado for /app_files/dev
, esse diretório conterá os seguintes arquivos e diretórios:
Um arquivo
manifest.yml
.Um diretório que contém o script de configuração, por exemplo
scripts/setup_version.sql
.Arquivos referenciados que são importados ao criar um procedimento armazenado, UDF ou função externa dentro do script de configuração, por exemplo:
libraries/jars/lookup.jar
libraries/jars/log4j.jar
libraries/python/evaluate.py
Nesse cenário, a estrutura de diretórios seria a seguinte:
@DEV_DB.DEV_SCHEMA.DEV_STAGE/V1:
└── app_files/
└── dev
├── manifest.yml
└── scripts/
├── setup_script.sql
└── libraries/
└── jars/
├── lookup.jar
└── log4j.jar
└── python
└── evaluation.py
Para acessar os arquivos JAR nessa estrutura de diretório, um procedimento armazenado definido no script de configuração faria referência a esses arquivos conforme mostrado no exemplo a seguir:
CREATE PROCEDURE PROGRAMS.LOOKUP(...)
RETURNS STRING
LANGUAGE JAVA
PACKAGES = ('com.snowflake:snowpark:latest')
IMPORTS = ('/scripts/libraries/jar/lookup.jar',
'/scripts/libraries/jar/log4j.jar')
HANDLER = 'com.acme.programs.Lookup';
Neste exemplo, a instrução IMPORTS tem um caminho relativo ao diretório raiz usado para criar a versão, por exemplo, o local do arquivo manifest.yml
.
Inclusão do código Java e Scala em um pacote de aplicativo¶
O Snowflake Native App Framework oferece suporte ao uso de Java e Scala em procedimentos armazenados e em arquivos de código externos.
Criação de UDFs de Java e Scala em linha¶
O Snowflake Native App Framework oferece suporte à criação de procedimentos armazenados contendo Java e Scala. O código que define o procedimento armazenado deve ser adicionado ao script de configuração.
O exemplo a seguir mostra um procedimento armazenado contendo uma função Java:
CREATE OR ALTER VERSIONED SCHEMA app_code;
CREATE STAGE app_code.app_jars;
CREATE FUNCTION app_code.add(x INT, y INT)
RETURNS INTEGER
LANGUAGE JAVA
HANDLER = 'TestAddFunc.add'
TARGET_PATH = '@app_code.app_jars/TestAddFunc.jar'
AS
$$
class TestAddFunc {
public static int add(int x, int y) {
Return x + y;
}
}
$$;
Importação de UDFs de Java e Scala externas¶
A sintaxe para criar UDFs pré-compiladas exige que os JARs importados sejam incluídos como parte de um conjunto de artefatos com versão. Para se referir aos JARs pré-compilados, use o caminho relativo em vez de especificar o local completo do estágio na cláusula IMPORT.
O caminho deve ser relativo ao diretório raiz que contém a versão que começa com uma única barra, por exemplo IMPORTS = ('/path/to/JARs/from/version/root')
. Consulte Referência a arquivos de código externos para obter mais informações sobre caminhos relativos.
A seguir é mostrado um exemplo de estrutura de diretório para os arquivos de código.
@DEV_DB.DEV_SCHEMA.DEV_STAGE/V1:
└── V1/
├── manifest.yml
├── setup_script.sql
└── JARs/
├── Java/
│ └── TestAddFunc.jar
└── Scala/
└── TestMulFunc.jar
O exemplo a seguir mostra como criar uma função Java usando um arquivo JAR:
CREATE FUNCTION app_code.add(x INTEGER, y INTEGER)
RETURNS INTEGER
LANGUAGE JAVA
HANDLER = 'TestAddFunc.add'
IMPORTS = ('/JARs/Java/TestAddFunc.jar');
Restrições em UDFs de Java e Scala¶
O Snowflake Native App Framework impõe as seguintes restrições ao usar Java e Scala:
As importações são permitidas apenas para UDFs criadas em um esquema com versão.
As importações só podem acessar os artefatos de versão usando um caminho relativo.
UDFs criadas fora dos esquemas com versão só podem ser criados em linha.
Caminhos relativos não são suportados para TARGET_PATH.
Adição do código Python a um pacote de aplicativo¶
O Snowflake Native App Framework oferece suporte ao uso do Python em procedimentos armazenados e em arquivos de código externos.
Definição de uma função Python no script de configuração¶
O Snowflake Native App Framework oferece suporte à criação de procedimentos armazenados em Python.
O exemplo a seguir mostra um procedimento armazenado contendo uma função Python:
CREATE FUNCTION app_code.py_echo_func(str STRING)
RETURNS STRING
LANGUAGE PYTHON
HANDLER = 'echo'
AS
$$
def echo(str):
return "ECHO: " + str
$$;
Uso de arquivos Python externos¶
O exemplo a seguir mostra como incluir um arquivo Python externo em um pacote de aplicativo:
CREATE FUNCTION PY_PROCESS_DATA_FUNC()
RETURNS STRING
LANGUAGE PYTHON
HANDLER = 'TestPythonFunc.process'
IMPORTS = ('/python_modules/TestPythonFunc.py',
'/python_modules/data.csv')
Consulte Referência a arquivos de código externos para obter mais informações sobre caminhos relativos.
Restrições de UDFs de Python¶
Snowflake Native App Framework impõe as seguintes restrições às UDFs de Python:
As importações são permitidas apenas para UDFs criadas em um esquema com versão.
As importações só podem acessar os artefatos de versão usando um caminho relativo.
UDFs criadas fora dos esquemas com versão só podem ser criados em linha.
Adição de funções e procedimentos JavaScript a um pacote de aplicativo¶
O Snowflake Native App Framework oferece suporte ao uso de JavaScript em procedimentos armazenados e funções definidas pelo usuário usando a API JavaScript.
Tratamento de erros de JavaScript¶
Ao usar JavaScript em um pacote de aplicativo, Snowflake recomenda que você detecte e lide com os erros. Caso contrário, a mensagem de erro e o rastreamento de pilha que o erro retorna ficam visíveis para o consumidor. Para garantir que o conteúdo dos dados e a lógica do aplicativo sejam mantidos privados, use blocos try/catch em situações em que objetos ou dados confidenciais estão sendo acessados.
O exemplo a seguir mostra um procedimento armazenado JavaScript que detecta um erro e retorna uma mensagem:
CREATE OR REPLACE PROCEDURE APP_SCHEMA.ERROR_CATCH()
RETURNS STRING
LANGUAGE JAVASCRIPT
EXECUTE AS OWNER
AS $$
try {
let x = y.length;
}
catch(err){
return "There is an error.";
}
return "Done";
$$;
Este exemplo cria um procedimento armazenado JavaScript que contém um bloco try/catch. Se o procedimento armazenado encontrar um erro ao executar a instrução no bloco try
, ele retornará a mensagem «There is an error”, que fica visível para o consumidor.
Sem o bloco try/catch, o procedimento armazenado retornaria a mensagem de erro original e o rastreamento de pilha completo que ficaria visível para o consumidor.
Nota
Outras linguagens suportadas pelo Snowflake Native App Framework retornam mensagens de erro redigidas que ocorrem em um Snowflake Native App.
Adição de funções externas a um pacote de aplicativo¶
As funções externas permitem que um Snowflake Native App faça chamadas para o código do aplicativo hospedado fora do Snowflake. As funções externas exigem que você crie um objeto de integração de API.
Como as integrações de API permitem conectividade fora do ambiente do consumidor, o consumidor deve fornecer o método de integração ao Snowflake Native App.
O exemplo a seguir mostra um procedimento armazenado criado pelo script de configuração que aceita a integração e cria uma função externa. Este exemplo mostra como criar uma função externa no script de configuração do pacote de aplicativo:
CREATE OR REPLACE PROCEDURE calculator.create_external_function(integration_name STRING)
RETURNS STRING
LANGUAGE SQL
EXECUTE AS OWNER
AS
DECLARE
CREATE_STATEMENT VARCHAR;
BEGIN
CREATE_STATEMENT := 'CREATE OR REPLACE EXTERNAL FUNCTION EXTERNAL_ADD(NUM1 FLOAT, NUM2 FLOAT)
RETURNS FLOAT API_INTEGRATION = ? AS ''https://xyz.execute-api.us-west-2.amazonaws.com/production/sum'';' ;
EXECUTE IMMEDIATE :CREATE_STATEMENT USING (INTEGRATION_NAME);
RETURN 'EXTERNAL FUNCTION CREATED';
END;
GRANT USAGE ON PROCEDURE calculator.create_external_function(string) TO APPLICATION ROLE app_public;
Este exemplo define um procedimento armazenado, escrito em SQL, e cria uma função externa que faz referência a um aplicativo hospedado em um sistema fora do Snowflake. A função externa retorna uma integração de API.
Este exemplo também concede USAGE no procedimento armazenado para uma função de aplicativo. O consumidor deve conceder esse privilégio ao Snowflake Native App antes de chamar esse procedimento no script de configuração.