Skip to main content
A stored procedure is a database object consisting of PL/pgSQL or SQL statements that can be issued with a single CALL statement. This allows complex logic to be executed repeatedly within the database, which can improve performance and mitigate security risks. 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 CALL statement. Functions can be invoked in nearly any context, such as SELECT, FROM, and WHERE clauses, DEFAULT expressions, and computed column expressions.
  • Functions have volatility settings, and procedures do not.

Structure

A stored procedure consists of a name, optional parameters, language, and procedure body.
For details, see CREATE PROCEDURE.

Examples

Setup

To follow along, run cockroach demo to start a temporary, in-memory cluster with the movr sample dataset preloaded:
For more examples of stored procedure creation, see CREATE PROCEDURE.

Create a stored procedure using PL/pgSQL

The following stored procedure removes a specified number of earliest rides in vehicle_location_histories. It uses the PL/pgSQL WHILE syntax to iterate through the rows, RAISE to return notice and error messages, and REFCURSOR to define a cursor that fetches the next rows to be affected by the procedure.
Open a transaction:
Call the stored procedure, specifying 5 rows to delete and a rides_left cursor name:
Use the cursor to fetch the 3 earliest remaining rows in vehicle_location_histories:
If the procedure is called again, these rows will be the first 3 to be deleted.

Example details

The example works as follows: CREATE PROCEDURE defines a stored procedure called delete_earliest_histories with an INT and a REFCURSOR parameter.
LANGUAGE specifies PL/pgSQL as the language for the stored procedure.
DECLARE specifies the PL/pgSQL variable definitions that are used in the procedure body.
BEGIN and END group the PL/pgSQL statements in the procedure body.
The following IF... THEN statement raises an exception if vehicle_location_histories has fewer rows than the number specified with num_deletions. If the exception is raised within an open transaction, the transaction will abort.
The following WHILE loop deletes rows iteratively from vehicle_location_histories, stopping when the number of loops reaches the num_deletions value. The DELETE... RETURNING... INTO statement assigns column values from each deleted row into separate variables. For more information about assigning variables, see Assign a result to a variable. Finally, the RAISE NOTICE statement reports these values for each deleted row.
The OPEN statement opens a cursor for all remaining rows in vehicle_location_histories, sorted by timestamp. After calling the procedure in an open transaction, the cursor can be used to fetch rows from the table.

Alter a stored procedure

The following statement renames the delete_earliest_histories example procedure to delete_histories:

Known limitations

Stored procedures have the following limitations:
  • COMMIT and ROLLBACK statements are not supported within nested procedures.
  • 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.
Also refer to the PL/pgSQL known limitations.

See also