What you will be able to do
- Tell scalar UDFs, UDTFs, UDAFs and vectorized variants apart by what each one takes in and returns
- Choose a handler language based on the variations it supports, where its handler code can live, and whether the UDF can be shared
- Write and call SQL and JavaScript UDFs, and explain owner-versus-invoker privileges
- Decide when to make a UDF SECURE, and what that costs and protects
Key concept
Handler — A handler is the code that holds a UDF's logic. You write it in a supported language (SQL, JavaScript, Python, Java or Scala). Snowflake runs it each time the function is called. The CREATE FUNCTION statement wraps the handler in a callable function name, its argument types and its return type.
1.What a UDF is, and its variations: scalar, UDTF, UDAF
A user-defined function (UDF) adds an operation that Snowflake's built-in functions don't provide. It can also wrap a calculation your organization repeats everywhere. After you create it, you call it the same way you call a built-in function, and you can reuse it as often as you like. A function always returns a value from an expression, so it fits work that computes something and hands it back.
The word "UDF" covers several variations. They differ in how many rows go in and how many come out. Exam questions often describe what goes in and what comes out, and expect you to name the variation.
| Variation | Input | Output |
|---|---|---|
| User-defined function (UDF), also called a scalar function | One row | One row with a single column/value |
| User-defined table function (UDTF) | One row | A tabular value (a set of rows) |
| User-defined aggregate function (UDAF) | Values across multiple rows | One aggregated result (sum, average, count, min/max, standard deviation, estimation and similar) |
| Vectorized UDF | Batches of rows as Pandas DataFrames | Batches of results as Pandas arrays or Series |
| Vectorized UDTF | Batches of rows as Pandas DataFrames | Tabular results |
Checkpoint 1 of 6· Match them up
Match each requirement to the UDF variation that meets it
Tap a term, then the definition that fits it.
The variations are defined by their input and output shapes: one value per row, a table per row, one result across many rows, or Pandas batches.
“Also known as a scalar function, returns one output row for each input row.”Source: docs.snowflake.com
Sources1
2.Handler languages, Snowpark (Java, Python, Scala) and sharability
There are two main ways to create a UDF. In SQL, you run CREATE FUNCTION with a handler written in Java, JavaScript, Python, Scala or SQL. In the Snowpark API, you write Java, Python or Scala code on the client, and Snowflake runs that code where the data is. The Snowflake CLI, the Snowflake Python API and the REST API can also create and manage functions.
The language you choose limits what you can build. Python is the only language that supports every variation. Through SQL, it covers UDF, UDAF, UDTF and both vectorized types. JavaScript and Java support UDFs and UDTFs. Scala supports scalar UDFs only when created through SQL, but both UDFs and UDTFs through Snowpark. SQL handlers support UDFs and UDTFs. No other language offers a UDAF.
| Language | Handler location | Sharable |
|---|---|---|
| Java | In-line or staged | No |
| JavaScript | In-line | Yes |
| Python | In-line or staged | No |
| Scala | In-line or staged | No |
| SQL | In-line | Yes |
Below is a Python handler written in-line in a CREATE FUNCTION statement. LANGUAGE names the handler language. HANDLER names the Python function to call. RUNTIME_VERSION pins the Python version. You call the result like any other function, for example SELECT addone(3);.
CREATE OR REPLACE FUNCTION addone(i INT)
RETURNS INT
LANGUAGE PYTHON
RUNTIME_VERSION = '3.12'
HANDLER = 'addone_py'
AS $$
def addone_py(i):
return i+1
$$;Two runtime details often come up in exam questions:
- If the handler calls CURRENT_DATABASE or CURRENT_SCHEMA, the result is the database or schema that contains the UDF, not the session's current one. - When reading staged files, UDTFs can process several files in parallel, but scalar UDFs currently process them one at a time.
Checkpoint 2 of 6· Check yourself
A team needs a custom aggregate function, created with CREATE FUNCTION. Which handler language must they use?
In the language support matrix, UDAF appears only under Python. Java, JavaScript and SQL support UDFs and UDTFs only.
“Java:UDF, UDTFJavaScript:UDF, UDTFPython:UDF, UDAF, UDTF, Vectorized UDF, Vectorized UDTFScala:UDFSQL:UDF, UDTF”Source: docs.snowflake.com
Checkpoint 3 of 6· Exam question
A data engineer wants to encapsulate a single repeated business calculation, converting a raw sensor reading to Celsius, so that every analyst-facing SQL query can call it as one reusable expression without duplicating the formula. No procedural branching or external library is required. Which approach fits this requirement best?
Correct answer: A — Create a SQL UDF with `CREATE FUNCTION` that wraps the conversion expression, since SQL UDFs execute purely as SQL and are the lightest option for a single reusable arithmetic expression.
- A. A SQL UDF is correct because it lets a single arithmetic expression be defined once with `CREATE FUNCTION` and then referenced inline in any query, with no scripting runtime or dependency overhead.
- B. This is incorrect because SQL UDFs can already be called inside a `SELECT` list; adding a JavaScript handler and exception handling for plain arithmetic introduces an unnecessary runtime for no functional gain.
- C. This is incorrect because a Python handler with an external package dependency is unwarranted for a simple formula, and numeric conversions do not require Python at all in Snowflake.
- D. This is incorrect because a scalar function, not a procedure, is the natural fit for a value consumed inline in a query, and stored procedures are not the only Snowflake objects that return values.
Sources1
3.SQL UDFs
A SQL UDF evaluates any SQL expression and returns the result. A plain definition returns one scalar value. A definition declared as a table function returns a set of rows. A SQL UDF needs no LANGUAGE or HANDLER clause, because the body between the $$ delimiters is the logic.
CREATE FUNCTION area_of_circle(radius FLOAT)
RETURNS FLOAT
AS
$$
pi() * radius * radius
$$
;The privilege model makes SQL UDFs useful for access control. If the definition names a table without a schema, Snowflake looks for it in the schema that contains the function. The function's owner must have privileges on every object the definition uses. The caller only needs privileges on the function itself. In the example below, an administrator exposes a user count without giving analysts access to the sensitive users table.
CREATE FUNCTION total_user_count() RETURNS NUMBER AS 'select count(*) from users';
GRANT USAGE ON FUNCTION total_user_count() TO ROLE analyst;When the analyst role runs SELECT * FROM users, the query fails because the role has no access to the table. When the same role runs SELECT total_user_count(), the query succeeds.
Checkpoint 4 of 6· Check yourself
Role analyst has USAGE on total_user_count() but no privileges on table users. What happens when analyst runs SELECT total_user_count()?
Objects in the definition are checked against the function owner's privileges. The caller only needs privileges on the function.
“The invoker of the function need not have access to the objects referenced in the function definition”Source: docs.snowflake.com
Sources2
4.JavaScript UDFs
A JavaScript UDF is created with SQL and adds LANGUAGE JAVASCRIPT. Snowflake converts arguments and return values between SQL types and JavaScript types. One rule catches many people: inside the JavaScript body, you must refer to parameter names in all uppercase, even if you declared them in lowercase in SQL. In the example, the parameter is declared as a but read as A.
-- Create the UDF.
CREATE OR REPLACE FUNCTION my_array_reverse(a ARRAY)
RETURNS ARRAY
LANGUAGE JAVASCRIPT
AS
$$
return A.reverse();
$$
;JavaScript handlers are always written in-line; they cannot live on a stage. Like SQL UDFs, JavaScript UDFs can be shared through Secure Data Sharing. Handler code can also write log and trace data while it runs.
Checkpoint 5 of 6· Fill the gap
The SQL signature declares the parameter as lowercase a. What must the JavaScript body use to refer to it?
-- Create the UDF.
CREATE OR REPLACE FUNCTION my_array_reverse(a ARRAY)
RETURNS ARRAY
LANGUAGE JAVASCRIPT
AS
$$
return ? .reverse();
$$
;JavaScript handlers must refer to input parameters in all uppercase, so a is read as A.
Source: docs.snowflake.comSources3
5.Secure UDFs
To hide a function's internals from users who shouldn't see them, add the SECURE keyword when you create or alter the UDF. A secure UDF protects two things.
First, it protects the definition. Only users granted a role that owns the function can see its body (the handler code), its list of imports, its handler name and its packages list. Other users can still see its parameter types, return type, handler language, null handling and volatility.
Second, it protects the data. Some internal optimizations for regular UDFs, such as pushdown, need access to the underlying base tables, and that access could reveal data hidden from the function's users. A secure UDF prevents this. For handlers written in Java, Python or Scala, SECURE also runs each function in its own sandbox, so no resources are shared between functions.
That cost is why the guidance is narrow. Make a UDF secure when its purpose is data privacy, meaning it limits access to sensitive data that not every user of the underlying tables should see. Don't make a UDF secure when it only exists to make queries more convenient.
Checkpoint 6 of 6· Check yourself
A non-owner queries a secure Python UDF. Which detail is hidden from them?
SECURE hides the body, imports, handler name and packages list from non-owners. The signature, return type and language stay visible.
“For a UDF or stored procedure, you can prevent users from seeing definition specifics.”Source: docs.snowflake.com
Sources4
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Declaring every UDF SECURE is a free security improvement.Why is that wrong?
Secure UDFs skip the optimizer shortcuts that regular UDFs get, so they can run slower. Use SECURE only for functions meant to protect data privacy, not for convenience functions.
Covered in Secure UDFs
2.A Python UDF can be shared with a consumer account through Secure Data Sharing.Why is that wrong?
Only UDFs with JavaScript or SQL handlers can be shared. Java, Python and Scala UDFs cannot.
Covered in Handler languages, Snowpark (Java, Python, Scala) and sharability
3.To call a SQL UDF that reads a table, the caller needs SELECT on that table.Why is that wrong?
Objects in the definition are checked against the function owner's privileges. The caller only needs privileges on the function.
Covered in SQL UDFs
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“Also known as a scalar function, returns one output row for each input row.”
↩︎ What a UDF is, and its variations: scalar, UDTF, UDAF“Returns a tabular value for each input row.”
↩︎ What a UDF is, and its variations: scalar, UDTF, UDAF“Not all languages support referring to the handler on a stage (the handler code must instead be in-line).”
↩︎ Handler languages, Snowpark (Java, Python, Scala) and sharability“the function returns the database or schema that contains the UDF, not the database or schema in use for the session.”
↩︎ Handler languages, Snowpark (Java, Python, Scala) and sharability“UDTFs can process multiple files in parallel; however, UDFs currently process files serially.”
↩︎ Handler languages, Snowpark (Java, Python, Scala) and sharability“Once you have a handler, you can create a UDF using any of several tools included in Snowflake, then execute the UDF.”
↩︎ Key concept“A sharable UDF can be used with the Snowflake Secure Data Sharing feature.”
↩︎ Exam trap 2“A sharable UDF can be used with the Snowflake Secure Data Sharing feature.”
↩︎ Prediction“Java:UDF, UDTFJavaScript:UDF, UDTFPython:UDF, UDAF, UDTF, Vectorized UDF, Vectorized UDTFScala:UDFSQL:UDF, UDTF”
↩︎ Checkpoint - 2.
“A SQL UDF evaluates an arbitrary SQL expression and returns the results of the expression.”
↩︎ SQL UDFs“If a function definition refers to an unqualified table, then that table is resolved in the schema containing the function.”
↩︎ SQL UDFs“The invoker of the function need not have access to the objects referenced in the function definition”
↩︎ Exam trap 3“The invoker of the function need not have access to the objects referenced in the function definition”
↩︎ Checkpoint - 3.https://docs.snowflake.com/en/developer-guide/udf/javascript/udf-javascript-introductionOfficial docs
“the JavaScript code must refer to the input parameter names as all uppercase, even if the names are not uppercase in the SQL code.”
↩︎ JavaScript UDFs - 4.
“you can use the SECURE keyword when creating a user-defined function (UDF) and stored procedure.”
↩︎ Secure UDFs“making the functions and procedures secure ensures that they are executed in separate sandboxes, such that no resources are shared between them.”
↩︎ Secure UDFs“Define a UDF as secure when it is specifically designated for data privacy”
↩︎ Secure UDFs“You should not make a UDF secure when it is defined for query convenience”
↩︎ Exam trap 1“bypasses the optimizations used for regular UDFs. This might reduce query performance for secure UDFs.”
↩︎ Prediction“For a UDF or stored procedure, you can prevent users from seeing definition specifics.”
↩︎ Checkpoint