Entwerfen von Java-UDFs¶
Dieses Thema bietet Unterstützung beim Entwerfen von Java-UDFs.
Unter diesem Thema:
Auswählen Ihrer Datentypen¶
Bevor Sie Ihren Code schreiben:
Wählen Sie die Datentypen aus, die Ihre Funktion als Argumente akzeptieren soll, und den Datentyp, den Ihre Funktion zurückgeben soll.
Berücksichtigen Sie die Zeitzonenproblematik.
Entscheiden Sie, wie NULL-Werte behandelt werden sollen.
Zuordnung von SQL-Java-Datentypen für Parameter und Rückgabetypen¶
Die folgende Tabelle zeigt die Typzuordnungen zwischen SQL und Java. Diese Zuordnungen gelten im Allgemeinen sowohl für die Argumente, die an die Java-UDF übergeben werden, als auch für die Werte, die von der UDF zurückgegeben werden. Es gibt jedoch einige Ausnahmen, die in Fußnoten ausgeführt werden.
Einige SQL-Datentypen (z. B. NUMBER) sind mit mehreren Java-Datentypen kompatibel (z. B. int, long). In diesen Fällen können Sie einen beliebigen Java-Datentyp verwenden, der genügend Kapazität hat, um die tatsächlich zu übergebenden Werte aufzunehmen. Wenn Sie einen SQL-Wert an einen inkompatiblen Java-Datentyp übergeben (oder umgekehrt), gibt Snowflake einen Fehler aus.
SQL-Typ |
Java-Typ |
Anmerkungen |
---|---|---|
NUMBER |
short |
Darf nicht null sein. Muss in den Bereich von short passen (ohne Bruchteil, und ganzzahliger Teil darf die max/min-Werte von short nicht überschreiten). |
NUMBER |
Short |
Muss in den Bereich von short passen (ohne Bruchteil, und ganzzahliger Teil darf die max/min-Werte von short nicht überschreiten). |
NUMBER |
int |
Darf nicht null sein. Muss in den Bereich von int passen (ohne Bruchteil, und ganzzahliger Teil darf die max/min-Werte von int nicht überschreiten). |
NUMBER |
Integer |
Muss in den Bereich von int passen (ohne Bruchteil, und ganzzahliger Teil darf die max/min-Werte von int nicht überschreiten). |
NUMBER |
long |
Darf nicht null sein. Muss in den Bereich von long passen (ohne Bruchteil, und ganzzahliger Teil darf die max/min-Werte von long nicht überschreiten). |
NUMBER |
Long |
Muss in den Bereich von long passen (ohne Bruchteil, und ganzzahliger Teil darf die max/min-Werte von long nicht überschreiten). |
NUMBER |
java.math.BigDecimal |
|
NUMBER |
java.math.BigInteger |
Muss in den Bereich von BigInteger passen (ohne Bruchteil). |
NUMBER |
String |
|
FLOAT |
double |
Darf nicht null sein. |
FLOAT |
Double |
|
FLOAT |
float |
Darf nicht null sein. Kann zu Genauigkeitsverlust führen. |
FLOAT |
Float |
Kann zu Genauigkeitsverlust führen. |
FLOAT |
String |
Kann zu Genauigkeitsverlust führen (float -> string-Konvertierung ist verlustbehaftet). |
VARCHAR |
String |
|
BINARY |
byte[] |
|
BINARY |
String |
Kodiert die binäre Zeichenfolge in hexadezimale Form. 4 |
BINARY |
InputStream |
Gibt den BINARY-Wert als eine Sequenz von Bytes aus. |
BOOLEAN |
boolean |
Darf nicht null sein. |
BOOLEAN |
Boolean |
|
BOOLEAN |
String |
|
DATE |
java.sql.Date |
|
DATE |
String |
Formatiert das Datum als |
TIME |
java.sql.Time |
|
TIME |
String |
Formatiert die Uhrzeit als |
TIMESTAMP_LTZ |
java.sql.Timestamp |
Muss in den Bereich von java.sql.Timestamp passen. 3 |
TIMESTAMP_LTZ |
String |
Das Ausgabeformat ist |
TIMESTAMP_NTZ |
java.sql.Timestamp |
Muss in den Bereich von java.sql.Timestamp passen. Behandelt die Gesamtbetrachtungszeit (Wall Clock Time) als Versatz von der Unix-Epoche (erzwingt effektiv eine UTC-Zeitzone). 3 |
TIMESTAMP_NTZ |
String |
Behandelt die Gesamtbetrachtungszeit (Wall Clock Time) als Versatz von der Unix-Epoche (erzwingt effektiv eine UTC-Zeitzone). Das Ausgabeformat ist |
TIMESTAMP_TZ |
java.sql.Timestamp |
Muss in den Bereich von java.sql.Timestamp passen. 3 |
TIMESTAMP_TZ |
String |
Das Ausgabeformat ist |
VARIANT |
Der Datentyp Variant ist eine Klasse im Snowpark-Paket. Weitere Informationen dazu finden Sie unter Unterstützte Typen aus dem Snowpark-Paket. Ein Beispiel dazu finden Sie unter Übergeben eines VARIANT-Werts an eine Inline-Java-UDF. |
|
OBJECT |
Map<String, String> |
Die Schlüssel der Zuordnung (Map) sind die Schlüssel des Objekts, und die Werte sind als Zeichenfolgen formatiert. |
OBJECT |
String |
Formatiert das Objekt als JSON-Zeichenfolge (z. B. |
ARRAY |
String[] |
Formatiert die Elemente des Arrays als Zeichenfolgen. |
ARRAY |
String |
Formatiert das Array als JSON-Zeichenfolge (z. B. |
GEOGRAPHY |
String |
Formatiert das Geography-Element als GeoJSON. |
GEOGRAPHY |
- 1(1,2)
Das Format stimmt mit dem Internet (RFC)-Zeitstempelformat
DY, DD MON YYYY HH24:MI:SS TZHTZM
überein, wie unter Zeitstempelformate beschrieben. Wenn ein Zeitzonenversatz (dieTZHTZM
-Komponente) vorhanden ist, handelt es sich in der Regel um Ziffern (z. B. steht-0700
für 7 Stunden hinter UTC). Wenn der ZeitzonenversatzZ
(für „Zulu“) anstelle von Ziffern angegeben wird, ist das gleichbedeutend mit „+0000“ (UTC).- 2
Das Format stimmt mit dem Internet (RFC)-Zeitstempelformat
DY, DD MON YYYY HH24:MI:SS
überein, wie unter Zeitstempelformate beschrieben. Wenn auf die Zeichenfolge ein Leerzeichen undZ
(für „Zulu“) folgt, wird der Versatz explizit mit „0000“ (UTC) angegeben.- 3(1,2,3,4,5,6,7,8)
Obwohl Snowflake Zeitwerte mit Nanosekundengenauigkeit speichern kann, bietet die java.sql.time-Bibliothek nur Millisekundengenauigkeit. Die Konvertierung zwischen Snowflake- und Java-Datentypen kann die effektive Genauigkeit auf Millisekunden reduzieren.
- 4(1,2,3,4,5,6)
Diese Typzuordnung wird bei der Konvertierung von SQL-Argumenten nach Java unterstützt, aber nicht bei der Konvertierung von Java-Rückgabetypen in SQL-Typen.
- 5
Java verfügt nicht über einen eigenen Datentyp für geographische Daten. Der Geography-Datentyp, auf den hier Bezug genommen wird, ist eine Klasse im Snowpark-Paket. Weitere Informationen dazu finden Sie unter Unterstützte Typen aus dem Snowpark-Paket.
Unterstützte Typen aus dem Snowpark-Paket¶
In einer benutzerdefinierten Funktion können Sie eine bestimmte Teilmenge von Typen verwenden, die im Snowpark-Java-Paket von Snowflake enthalten sind. Obwohl diese Typen für die Verwendung im Snowpark-Code gedacht sind, können einige davon auch in UDFs verwendet werden, da sie großen praktischen Wert haben. (Weitere Informationen zu Snowpark finden Sie in der Snowpark-Dokumentation).
Die in der folgenden Tabelle aufgeführten Snowpark-Typen werden im UDF-Code unterstützt. Sie können keine anderen Snowpark-Typen in UDF-Code verwenden, da diese dort nicht unterstützt werden.
Snowpark-Typ |
Erforderliche Snowpark-Version |
Beschreibung |
---|---|---|
1.2.0 oder höher |
Repräsentiert den GEOGRAPHY-Typ von Snowflake. Ein Beispiel für die Verwendung des Datentyps |
|
1.4.0 oder höher |
Stellt Snowflake-VARIANT-Daten dar. Ein Beispiel für die Verwendung des Datentyps |
Angeben des Snowpark-Pakets als UDF-Abhängigkeit¶
Wenn Sie UDF-Code entwickeln, der das Snowpark-Paket verwendet, müssen Sie Ihre Entwicklungsumgebung so einrichten, dass Sie Code mit Snowpark-Abhängigkeiten kompilieren und ausführen können. Weitere Informationen dazu finden Sie unter Einrichten anderer Entwicklungsumgebungen für Snowpark Java.
Bei der Bereitstellung einer UDF durch Ausführen der CREATE FUNCTION-Anweisung können Sie das Snowpark-Paket als Abhängigkeit angeben, ohne die JAR-Datei in einen Stagingbereich hochladen zu müssen (die Bibliothek ist bereits in Snowflake enthalten). Dazu geben Sie in der PACKAGES
-Klausel den Paketnamen und die Version an. Ein Syntaxbeispiel finden Sie unter Übergeben eines GEOGRAPHY-Werts an eine Inline-Java-UDF.
TIMESTAMP_LTZ-Werte und Zeitzonen¶
Ein Java-UDF ist weitgehend isoliert von der Umgebung, in der sie aufgerufen wird. Die Zeitzone wird jedoch von der aufrufenden Umgebung geerbt. Wenn die Sitzung des Aufrufers vor dem Aufruf der Java-UDF eine Standardzeitzone eingestellt hat, dann hat die Java-UDF die gleiche Standardzeitzone. Die Java-UDF verwendet dieselben Daten der IANA-Zeitzonendatenbank, die auch von der nativen TIMEZONE-Funktion in Snowflake SQL verwendet wird (d. h. Daten aus Release 2021a der Zeitzonendatenbank).
NULL-Werte¶
Snowflake unterstützt zwei verschiedene NULL-Werte: SQL NULL
und VARIANT JSON null
. (Weitere Informationen zu Snowflake VARIANT NULL finden Sie unter NULL-Werte.)
Java unterstützt einen null
-Wert, der nur für nicht primitive Datentypen gilt.
Ein SQL-NULL
-Argument für eine Java-UDF wird in den Java null
-Wert übersetzt, aber nur für Java-Datentypen, die null
unterstützen.
Ein zurückgegebener Java null
-Wert wird in SQL NULL
zurückübersetzt.
Arrays und variable Anzahl von Argumenten¶
Java-UDFs können Arrays von jedem der folgenden Java-Datentypen erhalten:
String
boolean
double
float
int
long
short
Der Datentyp von übergebenen SQL-Werten muss mit dem entsprechenden Java-Datentyp kompatibel sein. Weitere Informationen zur Datentypkompatibilität finden Sie unter Zuordnung von SQL-Java-Datentypen für Parameter und Rückgabetypen.
Die folgenden zusätzlichen Regeln gelten für jeden der angegebenen Java-Datentypen:
boolean: Das Snowflake-ARRAY darf nur BOOLEAN-Elemente und keine NULL-Werte enthalten.
int/short/long: Das Snowflake-ARRAY darf nur Festkomma-Elemente mit einer Skalierung von 0 enthalten und auch keine NULL-Werte.
float/double: Das Snowflake-ARRAY muss enthalten:
Das ARRAY darf keine NULL-Werte enthalten.
Java-Methoden können diese Arrays auf eine von zwei Arten erhalten:
Verwendung der Array-Funktion von Java.
Verwendung der Java-Funktion varargs (variable Anzahl von Argumenten).
In beiden Fällen muss Ihr SQL-Code ein ARRAY übergeben.
Werteübergabe via ARRAY¶
Deklarieren Sie den Java-Parameter als Array. In der folgenden Methode ist dritte Parameter beispielsweise ein String-Array:
static int myMethod(int fixedArgument1, int fixedArgument2, String[] stringArray)
Nachfolgend finden Sie ein vollständiges Beispiel:
Erstellen und Laden der Tabelle:
CREATE TABLE string_array_table(id INTEGER, a ARRAY); INSERT INTO string_array_table (id, a) SELECT 1, ARRAY_CONSTRUCT('Hello'); INSERT INTO string_array_table (id, a) SELECT 2, ARRAY_CONSTRUCT('Hello', 'Jay'); INSERT INTO string_array_table (id, a) SELECT 3, ARRAY_CONSTRUCT('Hello', 'Jay', 'Smith');Erstellen der UDF:
create or replace function concat_varchar_2(a ARRAY) returns varchar language java handler='TestFunc_2.concatVarchar2' target_path='@~/TestFunc_2.jar' as $$ class TestFunc_2 { public static String concatVarchar2(String[] strings) { return String.join(" ", strings); } } $$;Aufrufen der UDF:
SELECT concat_varchar_2(a) FROM string_array_table ORDER BY id; +---------------------+ | CONCAT_VARCHAR_2(A) | |---------------------| | Hello | | Hello Jay | | Hello Jay Smith | +---------------------+
Werteübergabe via varargs¶
Die Verwendung von varargs ist der Verwendung eines Arrays sehr ähnlich.
Verwenden Sie in Ihrem Java-Code den varargs-Deklarationsstil von Java:
static int myMethod(int fixedArgument1, int fixedArgument2, String ... stringArray)
Nachfolgend finden Sie ein vollständiges Beispiel. Der einzige wesentliche Unterschied zwischen diesem Beispiel und dem vorangegangenen Beispiel (für Arrays) ist die Deklaration der Parameter für die Methode.
Erstellen und Laden der Tabelle:
CREATE TABLE string_array_table(id INTEGER, a ARRAY); INSERT INTO string_array_table (id, a) SELECT 1, ARRAY_CONSTRUCT('Hello'); INSERT INTO string_array_table (id, a) SELECT 2, ARRAY_CONSTRUCT('Hello', 'Jay'); INSERT INTO string_array_table (id, a) SELECT 3, ARRAY_CONSTRUCT('Hello', 'Jay', 'Smith');Erstellen der UDF:
create or replace function concat_varchar(a ARRAY) returns varchar language java handler='TestFunc.concatVarchar' target_path='@~/TestFunc.jar' as $$ class TestFunc { public static String concatVarchar(String ... stringArray) { return String.join(" ", stringArray); } } $$;Aufrufen der UDF:
SELECT concat_varchar(a) FROM string_array_table ORDER BY id; +-------------------+ | CONCAT_VARCHAR(A) | |-------------------| | Hello | | Hello Jay | | Hello Jay Smith | +-------------------+
Entwerfen von Java-UDFs unter Berücksichtigung der Snowflake-bedingten Einschränkungen¶
Um die Stabilität in der Snowflake-Umgebung sicherzustellen, hat Snowflake die folgenden Einschränkungen für Java-UDFs definiert. Wenn nicht anders angegeben, werden diese Einschränkungen bei der Ausführung der Java-UDF durchgesetzt, nicht bei der Erstellung.
Speicher¶
Vermeiden Sie einen zu hohen Verbrauch von Speicher.
Große Datenwerte (typischerweise BINARY-, lange VARCHAR- oder große ARRAY- oder OBJECT- oder VARIANT-Datentypen) benötigen viel Arbeitsspeicher.
Eine zu große Stapeltiefe kann eine große Menge an Speicher verbrauchen. Snowflake hat einfache Funktionsaufrufe mit einer Verschachtelungstiefe von 50 Ebenen ohne Fehler getestet. Die praktische Maximalgrenze hängt davon ab, wie viele Informationen im Stapel abgelegt werden.
UDFs geben einen Fehler zurück, wenn sie zu viel Speicher verbrauchen. Das jeweilige Limit kann sich ändern.
Zeit¶
Vermeiden Sie Algorithmen, die pro Aufruf sehr viel Zeit benötigen.
Wenn eine UDF-Anweisung zu lange dauert, bricht Snowflake die SQL-Anweisung ab und gibt einen Fehler an den Benutzer zurück. Dieses Limit begrenzt die Auswirkungen (und Kosten) von Fehlern wie Endlosschleifen.
Bibliotheken¶
Obwohl Ihre Java-Methode Klassen und Methoden aus Standard-Java-Bibliotheken verwenden kann, deaktivieren die Sicherheitsrestriktionen von Snowflake einige Funktionen, wie z. B. das Schreiben in Dateien. Einzelheiten zu Bibliothekseinschränkungen finden Sie im Abschnitt Einsetzen von bewährten Sicherheitsmethoden.
Entwerfen der Klasse¶
Wenn eine SQL-Anweisung Ihre Java-UDF aufruft, ruft Snowflake eine Java-Methode auf, die Sie geschrieben haben. Ihre Java-Methode wird als „Handler-Methode“ oder kurz „Handler“ bezeichnet.
Wie bei jeder Java-Methode muss Ihre Methode als Teil einer Klasse deklariert werden. Ihre Handler-Methode kann eine statische Methode oder eine Instanzenmethode der Klasse sein. Wenn Ihr Handler eine Instanzenmethode ist und Ihre Klasse einen Konstruktor ohne Argumente definiert, ruft Snowflake den Konstruktor zur Initialisierungszeit auf, um eine Instanz Ihrer Klasse zu erstellen. Wenn Ihr Handler eine statische Methode ist, muss Ihre Klasse keinen Konstruktor haben.
Der Handler wird für jede an die Java-UDF übergebene Zeile einmal aufgerufen. (Hinweis: Es wird nicht für jede Zeile eine neue Instanz der Klasse erstellt. Snowflake kann die Handler-Methode derselben Instanz mehrmals aufrufen oder dieselbe statische Methode mehrmals aufrufen).
Um die Ausführung Ihres Codes zu optimieren, geht Snowflake davon aus, dass die Initialisierung langsam sein kann, während die Ausführung der Handler-Methode schnell ist. Snowflake verwendet ein längeres Timeout für die Ausführung der Initialisierung (einschließlich Zeit für Laden der UDF und Aufruf des Konstruktors der Klasse, die die Handler-Methode enthält, falls ein Konstruktor definiert ist) als für die Ausführung des Handlers (Zeit für Aufruf Ihres Handlers mit einer Zeile der Eingabe).
Weitere Informationen zum Entwerfen der Klasse finden Sie unter Erstellen von Java-UDFs.
Optimieren von Initialisierung und Steuerung des globalen Zustands in skalaren UDFs¶
Die meisten skalaren UDFs müssen den folgenden Richtlinien folgen:
Wenn Sie einen gemeinsamen Zustand (Shared State) initialisieren müssen, der sich über Zeilen hinweg nicht ändert, initialisieren Sie ihn im Konstruktor der UDF-Klasse.
Schreiben Sie Ihre Handler-Methode so, dass sie Thread-sicher ist.
Vermeiden Sie das Speichern und Freigeben eines dynamischen Zustands über Zeilen hinweg.
Wenn Ihre UDF diesen Richtlinien nicht folgen kann oder wenn Sie ein tieferes Verständnis der Gründe für diese Richtlinien wünschen, lesen Sie die nächsten Unterabschnitte.
Einführung¶
Snowflake erwartet, dass skalare UDFs unabhängig verarbeitet werden. Wenn Sie sich zwischen Aufrufen auf einen gemeinsamen Zustand verlassen, kann dies zu unerwartetem Verhalten führen, da das System Zeilen in beliebiger Reihenfolge verarbeiten und diese Aufrufe auf mehrere JVMs verteilen kann. Bei UDFs sollte es vermieden werden, dass sich beim Aufrufen der Handler-Methode auf einen gemeinsamen Zustand verlassen wird. Es gibt jedoch zwei Situationen, in denen Sie möglicherweise möchten, dass eine UDF einen gemeinsamen Zustand speichert:
Code, der teure Initialisierungslogik enthält, die nicht bei jeder Zeile wiederholt werden soll.
Code, der einen gemeinsamen Zustand über Zeilen hinweg nutzt, z. B. als Cache.
Wenn Sie den Zustand über mehrere Zeilen hinweg gemeinsam nutzen müssen und sich dieser Zustand im Laufe der Zeit nicht ändert, dann verwenden Sie einen Konstruktor, um den gemeinsamen Zustand durch das Einstellen von Variablen auf Instanzenebene zu erstellen. Der Konstruktor wird nur einmal pro Instanz ausgeführt, während der Handler einmal pro Zeile aufgerufen wird, sodass die Initialisierung im Konstruktor günstiger ist, wenn ein Handler mehrere Zeilen verarbeitet. Und da der Konstruktor nur einmal aufgerufen wird, muss er nicht thread-sicher geschrieben werden.
Wenn Ihre UDF einen gemeinsamen Zustand speichert, der sich ändert, muss Ihr Code darauf vorbereitet sein, den gleichzeitigen Zugriff mit diesem Zustand zu verarbeiten. In den nächsten beiden Abschnitten finden Sie weitere Informationen zur Parallelität und zum gemeinsamen Zustand.
Erläuterungen zur Java-UDF-Parallelisierung¶
Um die Verarbeitungsleistung zu verbessern, nutzt Snowflake die Parallelisierung sowohl zwischen mehrere JVMs als auch innerhalb von JVMs.
Mehrere JVMs:
Snowflake parallelisiert mehrere Ausführungen in einem Warehouse. Jede Ausführung nutzt eine (oder mehrere) JVMs. Dies bedeutet, dass es keinen globalen gemeinsamen Zustand gibt. Der Zustand kann höchstens innerhalb einer einzelnen JVM gemeinsam genutzt werden.
Innerhalb von JVMs:
Jede JVM kann mehrere Threads ausführen, die parallel die Handler-Methode der gleichen Instanz aufrufen können. Das bedeutet, dass jede Handler-Methode thread-sicher sein muss.
Wenn eine UDF mit IMMUTABLE eingerichtet ist und eine SQL-Anweisung diese UDF mehr als einmal mit denselben Argumenten für dieselbe Zeile aufruft, dann gibt die UDF bei jedem Aufruf für diese Zeile den gleichen Wert zurück. Im Folgenden wird z. B. zweimal derselbe Wert für jede Zeile zurückgegeben, wenn die UDF mit IMMUTABLE eingerichtet ist:
select my_java_udf(42), my_java_udf(42) from table1;
Wenn Sie möchten, dass mehrere Aufrufe unabhängige Werte zurückgeben, auch wenn die gleichen Argumente übergeben werden, und wenn Sie nicht die Funktion VOLATILE deklarieren möchten, dann binden Sie mehrere separate UDFs an die gleiche Handler-Methode. Beispiel:
Erstellen Sie eine JAR-Datei mit dem Namen
@java_udf_stage/rand.jar
mit Code:class MyClass { private double x; // Constructor public MyClass() { x = Math.random(); } // Handler public double myHandler() { return x; } }
Erstellen Sie die Java-UDFs wie unten gezeigt. Diese UDFs haben unterschiedliche Namen, verwenden aber die gleiche JAR-Datei und innerhalb dieser JAR-Datei den gleichen Handler.
create function my_java_udf_1() returns double language java imports = ('@java_udf_stage/rand.jar') handler = 'MyClass.myHandler'; create function my_java_udf_2() returns double language java imports = ('@java_udf_stage/rand.jar') handler = 'MyClass.myHandler';
Der folgende Code ruft beide UDFs auf. Die UDFs verweisen auf die gleiche JAR-Datei und den gleichen Handler. Diese Aufrufe erstellen zwei Instanzen der gleichen Klasse. Jede Instanz gibt einen unabhängigen Wert zurück, sodass das folgende Beispiel zwei unabhängige Werte zurückgibt, anstatt zweimal denselben Wert zu liefern:
select my_java_udf_1(), my_java_udf_2() from table1;
Speichern von JVM-Statusinformationen¶
Ein Grund, sich nicht auf einen dynamischen gemeinsamen Zustand zu verlassen, besteht darin, dass Zeilen nicht unbedingt in einer vorhersehbaren Reihenfolge verarbeitet werden. Bei jeder Ausführung einer SQL-Anweisung kann Snowflake die Anzahl der Batches, die Reihenfolge, in der die Batches verarbeitet werden, und die Reihenfolge der Zeilen innerhalb eines Batches variieren. Wenn eine skalare UDF so gestaltet ist, dass eine Zeile den Rückgabewert einer nachfolgenden Zeile beeinflusst, dann kann die UDF bei jeder Ausführung unterschiedliche Ergebnisse zurückgeben.
Fehlerbehandlung¶
Eine als UDF verwendete Java-Methode kann die üblichen Java-Techniken zur Ausnahmebehandlung verwenden, um Fehler innerhalb der Methode abzufangen.
Wenn eine Ausnahme innerhalb der Methode auftritt und nicht von der Methode abgefangen wird, gibt Snowflake einen Fehler aus, der die Stapelüberwachung für die Ausnahme enthält.
Sie können explizit einen Fehler auszulösen, ohne ihn abzufangen, um die Abfrage zu beenden und einen SQL-Fehler zu erzeugen. Beispiel:
if (x < 0) {
throw new IllegalArgumentException("x must be non-negative.");
}
Beim Debugging können Sie in den Text der SQL-Fehlermeldung Werte integrieren. Setzen Sie dazu den gesamten Textkörper der Java-Methode in einen „try-catch“-Block, und fügen Sie Argumentwerte zur abgefangenen Fehlermeldung hinzu. Lösen Sie dann einen Fehler mit der erweiterten Meldung aus. Um die Offenlegung sensibler Daten zu verhindern, entfernen Sie die Argumente, bevor Sie die JAR-Dateien in einer Produktionsumgebung bereitstellen.
Befolgen von Best Practices¶
Schreiben Sie plattformunabhängigen Code.
Vermeiden Sie Code, der eine bestimmte CPU-Architektur voraussetzt (z. B. x86).
Vermeiden Sie Code, der ein bestimmtes Betriebssystem voraussetzt.
Wenn Sie Initialisierungscode ausführen müssen und diesen nicht in die aufgerufene Methode aufnehmen möchten, können Sie den Initialisierungscode in einen statischen Initialisierungsblock einfügen.
Siehe auch:
Einsetzen von bewährten Sicherheitsmethoden¶
Ihre Methode (und alle Bibliotheksmethoden, die Sie aufrufen) muss sich wie eine reine Funktion verhalten, die nur auf die empfangenen Daten einwirkt und einen auf diesen Daten basierenden Wert zurückgibt, ohne Nebeneffekte zu verursachen. Ihr Code sollte nicht versuchen, den Zustand des zugrunde liegenden Systems zu beeinflussen, abgesehen davon, dass er eine angemessene Menge an Speicher und Prozessorzeit verbraucht.
Java-UDFs werden innerhalb einer eingeschränkten Engine ausgeführt. Weder Ihr Code noch der Code in den Bibliotheksmethoden, die Sie verwenden, darf irgendwelche verbotenen Systemaufrufe bereitstellen, einschließlich:
Prozesssteuerung Sie können z. B. einen Prozess nicht aufspalten. (Sie können jedoch mehrere Threads verwenden.)
Zugriff auf das Dateisystem.
Bis auf die folgenden Ausnahmen dürfen Java-UDFs keine Dateien lesen oder schreiben:
Java.UDFs können Dateien lesen, die in der
imports
-Klausel desCREATE FUNCTION
-Befehls angegeben sind. Weitere Informationen dazu finden Sie unter CREATE FUNCTION.Java-UDFs können Dateien, wie z. B. Protokolldateien, in das
/tmp
-Verzeichnis schreiben.Jede Abfrage erhält ein eigenes, mit Speicher unterstütztes Dateisystem mit eigenem „/tmp“-Verzeichnis, sodass bei verschiedenen Abfragen keine Dateinamenkonflikte auftreten können.
Konflikte innerhalb einer Abfrage sind jedoch möglich, wenn eine einzelne Abfrage mehr als eine UDF aufruft und diese UDFs versuchen, in Dateien mit demselben Namen zu schreiben.
Netzwerkzugriff.
Bemerkung
Da Ihr Code weder direkt noch indirekt auf das Netzwerk zugreifen kann, können Sie für den Zugriff auf die Datenbank nicht den Code im Snowflake-JDBC-Treiber verwenden. Ihre UDF kann selbst nicht als Client von Snowflake agieren.
JNI (Java Native Interface) wird nicht unterstützt. Snowflake verbietet das Laden von Bibliotheken, die nativen Code (im Gegensatz zu Java-Bytecode) enthalten.
Bei Verwendung innerhalb einer Region für Regierungsbehörden bieten Java-UDFs Unterstützung von Verschlüsselungsalgorithmen, die validiert wurden, um die Anforderungen des Federal Information Processing Standard (140-2) (FIPS 140-2) zu erfüllen. Es können nur solche kryptographischen Algorithmen verwendet werden, die im FIPS-geprüften Modus der BouncyCastle-Kryptographie-API für Java zugelassen sind. Weitere Informationen zu FIPS 140-2 finden Sie unter FIPS 140-2.