Hinzufügen von Anwendungslogik zu einem Anwendungspaket

Unter diesem Thema wird beschrieben, wie Sie dem Setup-Skript Ihrer Anwendung ein Anwendungspaket hinzufügen. Es wird auch beschrieben, wie Sie externe Codedateien in einem Anwendungspaket verwenden können.

Unter Hinzufügen einer Streamlit-App zu einem Anwendungspaket finden Sie Informationen zum Einbinden einer Streamlit-App in ein Anwendungspaket.

Hinweise zur Verwendung von gespeicherten Prozeduren und Funktionen

Das Snowflake Native App Framework bietet die Möglichkeit, gespeicherte Prozeduren, benutzerdefinierte Funktionen (UDFs) und externe Funktionen in ein Anwendungspaket einzubinden. Diese können in jeder der von Snowflake unterstützten Sprachen geschrieben werden.

Sicheres Hinzufügen von Anwendungscode

Alle gespeicherten Prozeduren und UDFs innerhalb einer Snowflake Native App werden wie die Anwendung selbst ausgeführt und haben Zugriff auf alle Objekte innerhalb der installierten Snowflake Native App. Dies kann zu Angriffen durch Einschleusen von SQL-Befehlen führen.

Daher empfiehlt Snowflake, dass bei der Entwicklung von Prozeduren und Funktionen zur Verwendung innerhalb einer Snowflake Native App alle SQL-Befehle, die Eingaben von Benutzern erfordern, mit gebundenen Parametern ausgeführt werden. Dazu zählen auch Eingaben, die über Prozedurargumente bereitgestellt werden.

Weitere Informationen dazu finden Sie unter Erstellen einer gespeicherten Prozedur.

Allgemeine Informationen zu Aufruferrechten und Eigentümerrechten

Alle Prozeduren, die durch das Setup-Skript erstellt oder aus der installierten Snowflake Native App heraus ausgeführt werden, müssen mit Eigentümerrechten (EXECUTE AS OWNER) ausgeführt werden.

Diese Einschränkung ist notwendig, da ansonsten beim Ausführen der Snowflake Native App mit Aufruferrechten (EXECUTE AS CALLER) für eine Prozedur, die der Snowflake Native App nicht gehört, die Prozedur als die Snowflake Native App selbst ausgeführt wird und es so Verbrauchern möglich wäre, Code zu erstellen, mit dem Inhalte der Snowflake Native App und freigegebene Dateninhalte offengelegt und geändert werden könnten.

Weitere Informationen dazu finden Sie unter Understanding Caller’s Rights and Owner’s Rights Stored Procedures.

Einschränkungen beim Aufrufen von Kontextfunktionen aus dem Setup-Skript

Kontextfunktionen liefern Informationen zu dem Kontext, in dem eine Anweisung ausgeführt wird. Im Kontext des Snowflake Native App Framework sind einige Kontextfunktionen nicht verfügbar. Kontextfunktionen, die nicht verfügbar sind, werden entweder blockiert und geben einen Fehler zurück oder sie geben immer einen Nullwert zurück.

Im Allgemeinen müssen Sie bei der Verwendung von Kontextfunktionen in Richtlinien, die auf freigegebenen Dateninhalten innerhalb einer Snowflake Native App angewendet werden, vorsichtig sein. Einige Funktionen, zum Beispiel CURRENT_IP_ADDRESS, verhalten sich im Kontext einer Snowflake Native App unterschiedlich.

Beachten Sie, dass es bei der Verwendung von Kontextfunktionen, die vom Namespace innerhalb der Client-Organisation abhängen, zu Konflikten mit Funktionen in anderen Namespaces kommen kann. Beispielsweise muss bei einer Zeilenzugriffsrichtlinie, die CURRENT_USER verwendet, berücksichtigt werden, dass derselbe Benutzername in mehreren Konten existieren kann.

In der folgenden Tabelle sind die Kontextfunktionen aufgeführt, die vom Snowflake Native App Framework nicht unterstützt werden:

Kontextfunktion

Blockiert in freigegebenem Inhalt (gibt null zurück)

Blockiert in Setup-Skripten und gespeicherten Prozeduren/UDFs, die der Snowflake Native App gehören (löst eine Ausnahme aus).

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

Verwenden von Snowpark-Funktionen und -Prozeduren in einer Anwendung

Das Snowflake Native App Framework unterstützt die Snowpark-Bibliotheken zum Erstellen von gespeicherten Prozeduren in Java, Scala und Python.

Referenzieren von externen Codedateien

Es gibt zwei Typen von Codedateien, die Sie in ein Anwendungspaket aufnehmen können:

  • Referenzierte Dateien: Enthalten Binärdateien, Bibliotheken und andere Codedateien. Diese Dateien sind spezifisch für eine in einem Anwendungspaket definierte Version. Diese Dateien müssen sich beim Erstellen oder beim Hinzufügen einer Version zu einem Anwendungspaket im Stammverzeichnis des Stagingbereichs befinden.

    Referenzierte Dateien unterscheiden sich von benutzerdefinierten Funktionen und gespeicherten Prozeduren dadurch, dass sie nicht im Setup-Skript eines Anwendungspakets definiert sind. Diese Dateien werden durch Importanweisungen in den gespeicherten Prozeduren und UDFs referenziert, die im Setup-Skript definiert sind.

  • Ressourcendateien: Umfassen semistrukturierte Daten, strukturierte Daten und Binärdateien, wie z. B. ein Machine Learning-Modell. Diese Dateien müssen in den benannten Stagingbereich hochgeladen werden, auf den das Anwendungspaket Zugriff hat.

Gespeicherte Prozeduren, benutzerdefinierte Funktionen oder externe Funktionen, die auf diese Typen von Codedateien verweisen, müssen innerhalb eines versionierten Schemas im Setup-Skript erstellt werden. Wenn Sie gespeicherte Prozeduren oder Funktionen innerhalb eines versionierten Schemas erstellen, müssen Sie eine Codedatei relativ zum Stammverzeichnis des benannten Stagingbereichs referenzieren.

Wenn das Stammverzeichnis des benannten Stagingbereichs beispielsweise /app_files/dev lautet, würde dieses Verzeichnis die folgenden Dateien und Verzeichnisse enthalten:

  • Eine manifest.yml-Datei

  • Ein Verzeichnis, das das Setup-Skript enthält, zum Beispiel scripts/setup_version.sql

  • Referenzierte Dateien, die beim Erstellen einer gespeicherten Prozedur, einer UDF oder einer externen Funktion innerhalb des Setup-Skripts importiert werden, wie z. B.:

    • libraries/jars/lookup.jar

    • libraries/jars/log4j.jar

    • libraries/python/evaluate.py

In diesem Szenario würde die Struktur des Verzeichnisses wie folgt aussehen:

@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
Copy

Um auf die JAR-Dateien in dieser Verzeichnisstruktur zuzugreifen, würde eine im Setup-Skript definierte gespeicherte Prozedur auf diese Dateien so verweisen, wie im folgenden Beispiel gezeigt:

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';
Copy

In diesem Beispiel verwendet die IMPORTS-Anweisung einen Pfad relativ zum Stammverzeichnis, das zum Erstellen der Version verwendet wurde, z. B. zum Speicherort der Datei manifest.yml.

Hinzufügen von Java- und Scala-Code zu einem Anwendungspaket

Das Snowflake Native App Framework unterstützt die Verwendung von Java und Scala in gespeicherten Prozeduren und in externen Codedateien.

Erstellen von Inline-UDFs in Java und Scala

Das Snowflake Native App Framework unterstützt das Erstellen von gespeicherten Prozeduren mit Java und Scala. Der Code, der die gespeicherte Prozedur definiert, muss dem Setup-Skript hinzugefügt werden.

Das folgende Beispiel zeigt eine gespeicherte Prozedur, die eine Java-Funktion enthält:

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;
       }
   }
 $$;
Copy

Importieren von externen Java- und Scala-UDFs

Die Syntax für das Erstellen von vorkompilierten UDFs erfordert, dass importierte JAR-Dateien als Teil eines Satzes von versionierten Artefakten enthalten sind. Um auf vorkompilierte JAR-Dateien zu verweisen, verwenden Sie in der IMPORT-Klausel den relativen Pfad, anstatt den vollständigen Pfad zum Stagingbereich anzugeben.

Der Pfad muss relativ zum Stammverzeichnis sein, das die Version enthält, beginnend mit einem einfachen Schrägstrich, zum Beispiel IMPORTS = ('/path/to/JARs/from/version/root'). Weitere Informationen zu relativen Pfadangaben finden Sie unter Referenzieren von externen Codedateien.

Im Folgenden finden Sie eine beispielhafte Verzeichnisstruktur für die Codedateien.

@DEV_DB.DEV_SCHEMA.DEV_STAGE/V1:
└── V1/
 ├── manifest.yml
 ├── setup_script.sql
 └── JARs/
     ├── Java/
     │   └── TestAddFunc.jar
     └── Scala/
         └── TestMulFunc.jar
Copy

Das folgende Beispiel zeigt, wie Sie eine Java-Funktion mithilfe einer JAR-Datei erstellen:

CREATE FUNCTION app_code.add(x INTEGER, y INTEGER)
  RETURNS INTEGER
  LANGUAGE JAVA
  HANDLER = 'TestAddFunc.add'
  IMPORTS = ('/JARs/Java/TestAddFunc.jar');
Copy

Einschränkungen bei Java- und Scala-UDFs

Das Snowflake Native App Framework sieht bei der Verwendung von Java und Scala die folgenden Einschränkungen vor:

  • Importe sind nur für UDFs zulässig, die in einem versionierten Schema erstellt wurden.

  • Importe können nur über einen relativen Pfad auf die Versionsartefakte zugreifen.

  • UDFs die außerhalb von versionierten Schemas erstellt wurden, können nur inline erstellt werden.

  • Relative Pfade werden für TARGET_PATH nicht unterstützt.

Hinzufügen von Python-Code zu einem Anwendungspaket

Das Snowflake Native App Framework unterstützt die Verwendung von Python in gespeicherten Prozeduren und in externen Codedateien.

Definieren einer Python-Funktion im Setup-Skript

Das Snowflake Native App Framework unterstützt das Erstellen von gespeicherten Prozeduren in Python.

Das folgende Beispiel zeigt eine gespeicherte Prozedur, die eine Python-Funktion enthält:

CREATE FUNCTION app_code.py_echo_func(str STRING)
RETURNS STRING
LANGUAGE PYTHON
HANDLER = 'echo'
AS
$$
  def echo(str):
    return "ECHO: " + str
$$;
Copy

Verwenden externer Python-Dateien

Im folgenden Beispiel wird gezeigt, wie Sie eine externe Python-Datei in ein Anwendungspaket aufnehmen können:

CREATE FUNCTION PY_PROCESS_DATA_FUNC()
  RETURNS STRING
  LANGUAGE PYTHON
  HANDLER = 'TestPythonFunc.process'
  IMPORTS = ('/python_modules/TestPythonFunc.py',
    '/python_modules/data.csv')
Copy

Weitere Informationen zu relativen Pfadangaben finden Sie unter Referenzieren von externen Codedateien.

Einschränkungen bei Python-UDFs

Das Snowflake Native App Framework sieht bei Python-UDFs die folgenden Einschränkungen vor:

  • Importe sind nur für UDFs zulässig, die in einem versionierten Schema erstellt wurden.

  • Importe können nur über einen relativen Pfad auf die Versionsartefakte zugreifen.

  • UDFs die außerhalb von versionierten Schemas erstellt wurden, können nur inline erstellt werden.

Hinzufügen von JavaScript-Funktionen und -Prozeduren zu einem Anwendungspaket

Das Snowflake Native App Framework unterstützt die Verwendung von in JavaScript geschriebenen gespeicherten Prozeduren und benutzerdefinierten Funktionen unter Verwendung der JavaScript-API.

Behandlung von JavaScript-Fehlern

Wenn Sie JavaScript innerhalb eines Anwendungspakets verwenden, empfiehlt Snowflake, dass Sie Fehler abfangen und behandeln. Wenn nicht, sind die Fehlermeldungen und die Stacküberwachung, die der Fehler zurückgibt, für den Verbraucher sichtbar. Um sicherzustellen, dass Dateninhalte und die Anwendungslogik nicht offengelegt werden, sollten Sie try/catch-Blöcke in Situationen verwenden, in denen auf sensible Objekte oder Daten zugegriffen wird.

Das folgende Beispiel zeigt eine gespeicherte JavaScript-Prozedur, die einen Fehler abfängt und eine Meldung zurückgibt:

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";
  $$;
Copy

In diesem Beispiel wird eine gespeicherte JavaScript-Prozedur erstellt, die einen try/catch-Block enthält: Wenn die gespeicherte Prozedur beim Ausführen der Anweisung im try-Block auf einen Fehler stößt, gibt sie die Meldung „There is an error“ (Es liegt ein Fehler vor) zurück, die für den Verbraucher sichtbar ist.

Ohne den try/catch-Block würde die gespeicherte Prozedur die ursprüngliche Fehlermeldung und die vollständige Stapelüberwachung zurückgeben und somit für den Verbraucher offenlegen.

Bemerkung

Andere vom Snowflake Native App Framework unterstützten Sprachen geben bei Fehlern, die in einer Snowflake Native App auftreten, eine ausgeblendete Fehlermeldung zurück.

Hinzufügen externer Funktionen zu einem Anwendungspaket

Mit externen Funktionen können Sie in einer Snowflake Native App Anwendungscode aufrufen, der außerhalb von Snowflake gehostet wird. Für externe Funktionen müssen Sie ein API-Integrationsobjekt erstellen.

Da die API-Integrationen Konnektivität außerhalb der Verbraucherumgebung ermöglichen, muss die Integrationsmethode für die Snowflake Native App vom Verbraucher bereitgestellt werden.

Das folgende Beispiel zeigt eine durch das Setup-Skript erstellte gespeicherte Prozedur, die die Integration akzeptiert und eine externe Funktion erstellt. Im folgenden Beispiel wird gezeigt, wie Sie eine externe Funktion im Setup-Skript des Anwendungspakets erstellen:

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;
Copy

In diesem Beispiel wird eine gespeicherte Prozedur definiert, die in SQL geschrieben ist und eine externe Funktion erstellt, die auf eine auf einem System außerhalb von Snowflake gehostete Anwendung verweist. Die externe Funktion gibt eine API-Integration zurück.

In diesem Beispiel wird außerdem einer Anwendungsrolle die Berechtigung USAGE für die gespeicherte Prozedur zugewiesen. Der Verbraucher muss der Snowflake Native App diese Berechtigung erteilen, bevor diese Prozedur im Setup-Skript aufgerufen wird.