Anwendungslogik zu einem Anwendungspaket hinzufügen¶
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 Benutzer-Frontend mit Streamlit zu einer App hinzufügen 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.
Anwendungscode sicher hinzufügen¶
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 |
✔ |
Snowpark-Funktionen und -Prozeduren in einem Anwendungspaket verwenden¶
Das Snowflake Native App Framework unterstützt die Snowpark-Bibliotheken zum Erstellen von gespeicherten Prozeduren in Java, Scala und Python.
Externen Codedateien referenzieren¶
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
-DateiEin 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
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';
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
.
Java- und Scala-Code in ein Anwendungspaket einbinden¶
Das Snowflake Native App Framework unterstützt die Verwendung von Java und Scala in gespeicherten Prozeduren und in externen Codedateien.
Java- und Scala-UDFs inline erstellen¶
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;
}
}
$$;
Externe Java- und Scala-UDFs importieren¶
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 Externen Codedateien referenzieren.
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
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');
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.
Python-Code zu einem Anwendungspaket hinzufügen¶
Das Snowflake Native App Framework unterstützt die Verwendung von Python in gespeicherten Prozeduren und in externen Codedateien.
Python-Funktion im Setup-Skript definieren¶
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
$$;
Externe Python-Dateien verwenden¶
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')
Weitere Informationen zu relativen Pfadangaben finden Sie unter Externen Codedateien referenzieren.
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.
JavaScript-Funktionen und -Prozeduren zu einem Anwendungspaket hinzufügen¶
Das Snowflake Native App Framework unterstützt die Verwendung von in JavaScript geschriebenen gespeicherten Prozeduren und benutzerdefinierten Funktionen unter Verwendung der JavaScript-API.
JavaScript-Fehler verarbeiten¶
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";
$$;
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.
Externe Funktionen zu einem Anwendungspaket hinzufügen¶
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;
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.