SELECT, FROM, and WHERE clauses of .
Both stored procedures and user-defined functions are types of routines. However, they differ in the following ways:
- Functions return a value, and procedures do not return a value.
- Procedures must be invoked using a statement. Functions can be invoked in nearly any context, such as
SELECT,FROM, andWHEREclauses, expressions, and expressions. - Functions have settings, and procedures do not.
Overview
The basic components of a user-defined function are a name, list of arguments, return type, volatility, language, and function body.- An argument has a mode and a type.
- CockroachDB supports the
IN(default),OUT, andINOUTargument modes. For an example, see . - The type can be a built-in type, or type, or implicit record type. A type can have a
DEFAULTvalue.
- CockroachDB supports the
- The return type can be a built-in , user-defined or type, , , PL/pgSQL type, implicit record type, , or
VOID.- Preceding a type with
SETOFindicates that a set, or multiple rows, may be returned. For an example, see . VOIDindicates that there is no return type andNULLwill always be returned.
- Preceding a type with
- The indicates whether the function has side effects.
VOLATILEandNOT LEAKPROOFare the default.- Annotate a function with side effects with
VOLATILE. This also prevents the from pre-evaluating the function. - A
STABLEorIMMUTABLEfunction does not mutate data. You cannot create aSTABLEorIMMUTABLEfunction that executes a mutation (INSERT,UPSERT,UPDATE,DELETE) statement. LEAKPROOFindicates that a function has no side effects and that it communicates nothing that depends on its arguments besides the return value (i.e., it cannot throw an error that depends on the value of its arguments). You must precedeLEAKPROOFwithIMMUTABLE, and onlyIMMUTABLEcan be set toLEAKPROOF.NOT LEAKPROOFis allowed with any other volatility.- Non-
VOLATILEfunctions can be optimized through inlining. For more information, see Create an inlined UDF.
- Annotate a function with side effects with
LANGUAGEspecifies the language of the function body. CockroachDB supports the languagesSQLand .- The function body:
- Can reference arguments by name or by their ordinal in the function definition with the syntax
$1. - Can be enclosed in a single line with single quotes
''or multiple lines with$$. - Can reference tables.
- Can reference only the
SELECTstatement.
- Can reference arguments by name or by their ordinal in the function definition with the syntax
Examples
Create a UDF
The following is a UDF that returns the sum of two integers:- name:
add - arguments:
aof typeINT,bof typeINT - return type:
INT - volatility:
IMMUTABLE LEAKPROOF - language:
SQL - function body:
'SELECT a + b'
View a UDF definition
To view the definition for theadd() function:
add when you create it, the default schema is public:
Invoke a UDF
You invoke a UDF like a . To invoke theadd() function:
Create a UDF using PL/pgSQL
The following user-defined function returns thenth integer in the Fibonacci sequence.
It uses the PL/pgSQL syntax to iterate through a simple calculation, and to return an error message if the specified n is negative.
Create an inlined UDF
When possible, the will improve a function’s performance by inlining the UDF within the query plan. The UDF must have the following attributes:- It is labeled as
IMMUTABLE,STABLE, orLEAKPROOF(i.e., non-VOLATILE). - It has a single statement.
- It is not a .
- Its arguments are only variable or constant expressions.
- It is not a .
-
Create tables
aandb: -
Insert a value (
10) into 1000 rows inaand 1 row inb: -
Create a
VOLATILEfunctionfoo_v()and aSTABLEfunctionfoo_s():Each function returns a specified value from tableb. -
View the query plan when
foo_v()(theVOLATILEfunction) is used in a selection query to retrieve equal values from tablea:The query takes77msto execute because the function is invoked for each row scanned in tablea. -
View the query plan when using
foo_s()(theSTABLEfunction) instead:The query takes only4msto execute because the function is inlined and transformed to a with an equality comparison(a) = (b), which has much less overhead than invoking a function for each row scanned in tablea.
Video Demo
For a deep-dive demo on UDFs, watch the following video: 1, b => 2);orSELECT foo(b := 1, a := 2);`.
- Routines cannot be created if they reference temporary tables.
- Routines cannot be created with unnamed
INOUTparameters. For example,CREATE PROCEDURE p(INOUT INT) AS $$ BEGIN NULL; END; $$ LANGUAGE PLpgSQL;. - Routines cannot be created if they return fewer columns than declared. For example,
CREATE FUNCTION f(OUT sum INT, INOUT a INT, INOUT b INT) LANGUAGE SQL AS $$ SELECT (a + b, b); $$;. - Routines cannot be created with an
OUTparameter of typeRECORD. - DDL statements (e.g.,
CREATE TABLE,CREATE INDEX) are not allowed within UDFs or stored procedures. - Polymorphic types cannot be cast to other types (e.g.,
TEXT) within routine parameters. - Routine parameters and return types cannot be declared using the
ANYENUMpolymorphic type, which is able to match any type. 123048

