What you will be able to do
- Explain what a stored procedure adds to Snowflake and where its handler code can live
- Write a Snowflake Scripting procedure that binds arguments with a colon and uses IN and OUT arguments
- Avoid the argument-case and library restrictions of JavaScript procedures
- Write a Snowpark Python procedure handler that receives a Session object
Key concept
Stored procedure handler — A stored procedure is two things: a SQL object you create with CREATE PROCEDURE and run with CALL, and a handler that holds the actual logic. The handler can be written in Snowflake Scripting, JavaScript, Python, Java or Scala. Which language you choose decides how you run SQL from inside the procedure and where the code can be stored.
1.What a stored procedure is for, and where its handler lives
A stored procedure lets you extend Snowflake with procedural code: branching, looping and other programming constructs that plain SQL statements lack. The usual reason to write one is to automate work that takes several database operations and runs often. The documentation's example is a cleanup job that deletes data older than a cutoff date from many tables. You put every DELETE inside one procedure and pass the cutoff date in as a parameter. Users then call that one procedure instead of having to remember each table name. A procedure can also build and run SQL dynamically.
Procedures have one more ability that matters for governance. A procedure can run with the privileges of the role that owns it, not the role that calls it. The owner can then let users perform specific operations they could not otherwise run, although owner's-rights procedures come with limitations.
The workflow is the same in every language. You write a handler, create the procedure with CREATE PROCEDURE, then run it with CALL. A procedure can return a single value or, if the handler language supports it, tabular data. Languages differ in one practical way: where the handler code can be stored.
| Handler language | Handler location |
|---|---|
| Java | In-line or staged |
| JavaScript | In-line |
| Python | In-line or staged |
| Scala | In-line or staged |
| Snowflake Scripting | In-line |
You don't always need a permanent procedure. A temporary procedure, created with CREATE PROCEDURE ... TEMPORARY or through the Snowpark API for Java, Python or Scala, lasts only for the current session. An anonymous procedure is created and called in a single statement and is dropped right after it runs. Neither approach requires the CREATE PROCEDURE privilege.
Checkpoint 1 of 8· Check yourself
A team wants to keep a procedure's handler code in a file on a stage, not in-line in the CREATE PROCEDURE statement. Which handler language cannot do this?
Java, Python and Scala handlers can be in-line or staged. JavaScript (like Snowflake Scripting) supports only in-line handlers.
“Not all languages support referring to the handler on a stage (the handler code must instead be in-line).”Source: docs.snowflake.com
Checkpoint 2 of 8· Exam question
By default, when a stored procedure is created in Snowflake without specifying an `EXECUTE AS` clause, which privilege model does it run under?
Correct answer: A — Owner's rights, meaning the procedure runs mostly with the privileges of whichever role owns the procedure, not the caller
- A. Correct — Snowflake stored procedures default to owner's rights unless EXECUTE AS CALLER is specified at creation, so the procedure runs mostly under the privileges of the role that owns it.
- B. Caller's rights is the alternative model, but it only applies when EXECUTE AS CALLER is explicitly declared in the CREATE PROCEDURE statement; it is not the default.
- C. Snowflake does not blend owner and caller privileges into a single hybrid session for a procedure call — each procedure picks exactly one model at creation time.
- D. A procedure always executes under either the owner's or caller's privileges from the moment it starts; there is no state where no role applies to the executing statements.
Sources1
2.Snowflake Scripting procedures (LANGUAGE SQL)
To write a procedure in SQL, use CREATE PROCEDURE with LANGUAGE SQL and put a Snowflake Scripting block (BEGIN ... END) in the AS clause. In Snowflake CLI, the Classic Console, or the Python Connector's execute_stream and execute_string methods, you must wrap the body in string literal delimiters (' or $$). Anonymous procedures always need those delimiters. Snowflake recommends keeping the body under 100 KB.
CREATE OR REPLACE PROCEDURE output_message(message VARCHAR)
RETURNS VARCHAR NOT NULL
LANGUAGE SQL
AS
BEGIN
RETURN message;
END;In a Scripting expression such as an IF or a RETURN, you refer to an argument by its plain name. Inside an embedded SQL statement, you must bind it by putting a colon in front of the name. A procedure can also return a table: declare a RESULTSET and return it with RETURN TABLE(...).
Checkpoint 3 of 8· Fill the gap
This procedure filters invoices by the id argument. What goes in the blank in the WHERE clause?
CREATE OR REPLACE PROCEDURE find_invoice_by_id(id VARCHAR)
RETURNS TABLE (id INTEGER, price NUMBER(12,2))
LANGUAGE SQL
AS
DECLARE
res RESULTSET DEFAULT (SELECT * FROM invoices WHERE id = ? );
BEGIN
RETURN TABLE(res);
END;Inside a SQL statement, an argument has to be bound with a colon prefix. Without it, id would refer to the column, not the argument.
Source: docs.snowflake.comScripting procedures accept both input and output arguments, declared as <arg_name> [ { IN | INPUT | OUT | OUTPUT } ] <arg_data_type>, with IN as the default. An IN argument becomes a variable you can change inside the body, but its final value never goes back to the caller. An OUT argument's final value is returned to the calling program, such as an anonymous block or another procedure. The rules: you can assign to an OUT argument only through a variable, and one variable can't serve two OUT arguments. OUT arguments can't have a DEFAULT, can't receive session variables, and can't be used in asynchronous child jobs. UDFs don't support OUT arguments. A procedure can take at most 500 arguments in total.
One more restriction: you can't overload a procedure by changing only the argument types. If test_overloading(a IN NUMBER) exists, creating test_overloading(a OUT NUMBER) fails because the procedure already exists.
Checkpoint 4 of 8· Check yourself
You need a procedure to hand a computed total back to a calling procedure through an OUT argument. Which handler language must you use?
Output arguments exist only in SQL (Snowflake Scripting) procedures. Procedures in other languages, and UDFs, don't support them.
“Stored procedures written in languages other than SQL don’t support output arguments.”Source: docs.snowflake.com
Sources2
3.JavaScript procedures and the snowflake object
A JavaScript handler runs SQL through an API built from four objects. snowflake is always available without being declared, and it creates statements and executes SQL. A Statement runs a prepared statement and exposes its metadata. A ResultSet holds the rows a query returns. SfDate is the return type for TIMESTAMP_LTZ, TIMESTAMP_NTZ and TIMESTAMP_TZ values. A typical handler calls snowflake.createStatement({sqlText: ...}), executes it, then reads values with next() and getColumnValue().
Checkpoint 5 of 8· Match them up
Match each JavaScript stored procedure API object to its role
Tap a term, then the definition that fits it.
The snowflake object is the entry point. It creates Statements, Statements produce ResultSets, and SfDate represents Snowflake timestamps in JavaScript.
“ResultSet, which holds the results of a query”Source: docs.snowflake.com
CREATE PROCEDURE f(argument1 VARCHAR)
RETURNS VARCHAR
LANGUAGE JAVASCRIPT
AS
$$
var local_variable1 = argument1; // Incorrect
var local_variable2 = ARGUMENT1; // Correct
$$;The mismatch can make a procedure fail without an explicit error, so use uppercase argument names consistently. The JavaScript engine is also restricted. You can't call eval(), and you can't import third-party libraries, only the standard JavaScript library. The engine blocks system calls, so there is no network or disk access, and its memory is limited. Watch numeric precision too: JavaScript keeps integers exact only up to ±(2^53 − 1). If a large NUMBER loses precision, read it with getColumnValueAsString() and cast it back in SQL.
Checkpoint 6 of 8· Check yourself
A developer wants a JavaScript procedure to load an npm library that parses dates. What happens?
JavaScript procedures can use only the standard JavaScript library. Snowflake blocks third-party libraries for security reasons.
“There is no mechanism to import, include, or call additional libraries.”Source: docs.snowflake.com
Sources3
4.Snowpark Python procedures: the Session is passed in
A Snowpark procedure works differently from a JavaScript one. You don't build SQL strings. The handler gets a Snowpark Session and works through the DataFrame API. In CREATE PROCEDURE you set LANGUAGE PYTHON, a RUNTIME_VERSION, the snowflake-snowpark-python package, and HANDLER, which names the function to call.
CREATE OR REPLACE PROCEDURE myproc(from_table STRING, to_table STRING, count INT)
RETURNS STRING
LANGUAGE PYTHON
RUNTIME_VERSION = '3.12'
PACKAGES = ('snowflake-snowpark-python')
HANDLER = 'run'
as
$$
def run(session, from_table, to_table, count):
session.table(from_table).limit(count).write.save_as_table(to_table)
return "SUCCESS"
$$;The Session parameter does not appear in the SQL signature, which declares only from_table, to_table and count. On every call, Snowflake creates a Session and passes it as the first argument. You cannot create one yourself. All other arguments and the return value use the Python types that map to Snowflake data types, and errors are caught with ordinary Python exception handling.
There are two operational details to know. The snowflake-snowpark-python library inside procedures is usually one version behind the public release, and you can check the available versions in information_schema.packages. Also, "fire and forget" doesn't work: if the handler starts an asynchronous child query (for example with DataFrame.collect_nowait) and that query is still running when the procedure finishes, the child job is canceled.
Checkpoint 7 of 8· Check yourself
In the myproc example, how does the run function get its session argument?
The Session comes from Snowflake, not from the caller or the handler. The CALL passes only the declared SQL arguments.
“When you call your stored procedure, Snowflake automatically creates a Session object and passes it to your stored procedure.”Source: docs.snowflake.com
Checkpoint 8 of 8· Exam question
A data engineering team builds a stored procedure that must read a session variable the calling application sets with `SET` before invoking it, then use that value inside a dynamic query. Which design lets the procedure read that caller-set session variable?
Correct answer: A — Create the procedure with `EXECUTE AS CALLER` so it runs with the invoking session's own privileges and can see that session's variables
- A. Correct — a caller's rights procedure executes with the invoking session's own privileges and session context, so it can read session variables like ones set with SET before the call.
- B. Passing the variable explicitly as an argument would work as a workaround, but it changes the interface entirely and does not let the procedure read the session variable directly as required here.
- C. Owner's rights procedures run mostly under the owner's privileges and cannot see the caller's session variables or most session parameters, so leaving the clause unspecified would not meet this requirement.
- D. There is no SESSION privilege that grants a procedure owner visibility into another user's active session variables; caller's rights execution is the mechanism that provides that access.
Sources4
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Any stored procedure can return values to its caller through OUT arguments.Why is that wrong?
Only Snowflake Scripting (SQL) procedures support output arguments. JavaScript, Python, Java and Scala procedures do not, and neither do UDFs.
2.In a JavaScript procedure, you refer to an argument using the same case you declared it with.Why is that wrong?
Unquoted argument names are uppercased on the SQL side, but JavaScript is case-sensitive, so a lowercase reference doesn't find the argument and can fail silently.
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-overviewOfficial docs
“Execute code with the privileges of the role that owns the procedure, rather than with the privileges of the role that runs the procedure.”
↩︎ What a stored procedure is for, and where its handler lives“creating a procedure in one of the following ways doesn’t require the CREATE PROCEDURE privilege”
↩︎ What a stored procedure is for, and where its handler lives“You write a procedure’s logic — its handler — in one of the supported languages.”
↩︎ Key concept“Not all languages support referring to the handler on a stage (the handler code must instead be in-line).”
↩︎ Checkpoint - 2.https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-snowflake-scriptingOfficial docs
“In the body of the stored procedure (the AS clause), you use a Snowflake Scripting block.”
↩︎ Snowflake Scripting procedures (LANGUAGE SQL)“if you need to use an argument in a SQL statement, put a colon (:) in front of the argument name.”
↩︎ Snowflake Scripting procedures (LANGUAGE SQL)“A stored procedure can’t be overloaded by specifying different argument types in the signature.”
↩︎ Snowflake Scripting procedures (LANGUAGE SQL)“Stored procedures written in languages other than SQL don’t support output arguments.”
↩︎ Exam trap 1“Stored procedures written in languages other than SQL don’t support output arguments.”
↩︎ Checkpoint - 3.https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-javascriptOfficial docs
“This code uses an object named snowflake, which is a special object that exists without being declared.”
↩︎ JavaScript procedures and the snowflake object“Retrieving a value from Snowflake and storing it in a JavaScript numeric variable can result in loss of precision.”
↩︎ JavaScript procedures and the snowflake object“Argument names are case-insensitive in the SQL portion of the stored procedure code, but are case-sensitive in the JavaScript portion.”
↩︎ Exam trap 2“ResultSet, which holds the results of a query”
↩︎ Checkpoint“Argument names are case-insensitive in the SQL portion of the stored procedure code, but are case-sensitive in the JavaScript portion.”
↩︎ Prediction“There is no mechanism to import, include, or call additional libraries.”
↩︎ Checkpoint - 4.https://docs.snowflake.com/en/developer-guide/stored-procedure/python/procedure-python-writingOfficial docs
“Specify the Snowpark Session object as the first argument of your method or function.”
↩︎ Snowpark Python procedures: the Session is passed in“if the handler issues a child query that is still running when the parent procedure job completes, the child job is canceled automatically.”
↩︎ Snowpark Python procedures: the Session is passed in“usually one version behind the publicly released version”
↩︎ Snowpark Python procedures: the Session is passed in“When you call your stored procedure, Snowflake automatically creates a Session object and passes it to your stored procedure.”
↩︎ Checkpoint