Skip to main content
A user-defined function (UDF) is a named function defined at the database level that can be called in queries and other contexts. CockroachDB supports invoking UDFs in SELECT, FROM, and WHERE clauses of . Both 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, and WHERE clauses, 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, and INOUT argument modes. For an example, see .
    • The type can be a built-in type, or type, or implicit record type. A type can have a DEFAULT value.
  • The return type can be a built-in , user-defined or type, , PL/pgSQL type, implicit record type, , or VOID.
    • Preceding a type with SETOF indicates that a set, or multiple rows, may be returned. For an example, see .
    • VOID indicates that there is no return type and NULL will always be returned.
  • The indicates whether the function has side effects. VOLATILE and NOT LEAKPROOF are the default.
    • Annotate a function with side effects with VOLATILE. This also prevents the from pre-evaluating the function.
    • A STABLE or IMMUTABLE function does not mutate data. You cannot create a STABLE or IMMUTABLE function that executes a mutation ( INSERT, UPSERT, UPDATE, DELETE ) statement.
    • LEAKPROOF indicates 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 precede LEAKPROOF with IMMUTABLE, and only IMMUTABLE can be set to LEAKPROOF. NOT LEAKPROOF is allowed with any other volatility.
    • Non- VOLATILE functions can be optimized through inlining. For more information, see Create an inlined UDF.
  • LANGUAGE specifies the language of the function body. CockroachDB supports the languages SQL and .
  • 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 SELECT statement.

Examples

Create a UDF

The following is a UDF that returns the sum of two integers:
Where:
  • name: add
  • arguments: a of type INT, b of type INT
  • return type: INT
  • volatility: IMMUTABLE LEAKPROOF
  • language: SQL
  • function body: 'SELECT a + b'
Alternatively, you could define this function as:
Or as:
For more examples of UDF creation, see .

View a UDF definition

To view the definition for the add() function:
If you do not specify a schema for the function add when you create it, the default schema is public:

Invoke a UDF

You invoke a UDF like a . To invoke the add() function:

Create a UDF using PL/pgSQL

The following user-defined function returns the nth integer in the Fibonacci sequence. It uses the 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, or LEAKPROOF (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 .
The following example demonstrates how inlining improves a UDF’s performance.
  1. Create tables a and b:
  2. Insert a value (10) into 1000 rows in a and 1 row in b:
  3. Create a VOLATILE function foo_v() and a STABLE function foo_s():
    Each function returns a specified value from table b.
  4. View the query plan when foo_v() (the VOLATILE function) is used in a selection query to retrieve equal values from table a:
    The query takes 77ms to execute because the function is invoked for each row scanned in table a.
  5. View the query plan when using foo_s() (the STABLE function) instead:
    The query takes only 4ms to 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 table a.

Video Demo

For a deep-dive demo on UDFs, watch the following video:

Known limitations

User-defined functions have the following limitations:
  • A RECORD -returning UDF cannot be created without a RETURN statement in the root block, which would restrict the wildcard type to a concrete one.
  • User-defined functions are not currently supported in:
    • Expressions (column, index, constraint) in tables.
    • Views.
  • User-defined functions cannot call themselves recursively.
  • (CTE), recursive or non-recursive, are not supported in (UDF). That is, you cannot use a WITH clause in the body of a UDF.
  • The setval function cannot be resolved when used inside UDF bodies.
  • Casting subqueries to in UDFs is not supported.
  • Routines cannot be invoked with named arguments, e.g., SELECT foo(a => 1, b => 2); or SELECT foo(b:= 1, a:= 2);.
  • Routines cannot be created if they reference temporary tables.
  • Routines cannot be created with unnamed INOUT parameters. 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 OUT parameter of type RECORD.
  • 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 ANYENUM polymorphic type, which is able to match any type. 123048
Also refer to the .

See also